bzoj 2007: [Noi2010]海拔

7 篇文章 0 订阅
2 篇文章 0 订阅

题意:

YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域。简单起见,可以将YT市看作一个
正方形,每一个区域也可看作一个正方形。从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路
(简称道路),每条双向道路连接主干道上两个相邻的交叉路口。下图为一张YT市的地图(n = 2),城市被划分为2
×2个区域,包括3×3个交叉路口和12条双向道路。 小Z作为该市的市长,他根据统计信息得到了每天上班高峰期
间YT市每条道路两个方向的人流量,即在高峰期间沿着该方向通过这条道路的人数。每一个交叉路口都有不同的海
拔高度值,YT市市民认为爬坡是一件非常累的事情,每向上爬h的高度,就需要消耗h的体力。如果是下坡的话,则
不需要耗费体力。因此如果一段道路的终点海拔减去起点海拔的值为h(注意h可能是负数),那么一个人经过这段路
所消耗的体力是max{0, h}(这里max{a, b}表示取a, b两个值中的较大值)。 小Z还测量得到这个城市西北角的交
叉路口海拔为0,东南角的交叉路口海拔为1(如上图所示),但其它交叉路口的海拔高度都无法得知。小Z想知道在
最理想的情况下(即你可以任意假设其他路口的海拔高度),每天上班高峰期间所有人爬坡所消耗的总体力和的最
小值。

题解:

终于想出一道平面图的题了(狼抓兔子不算)
首先,xjb猜两个结论:
1:面个点的海拔一定是0或1
2:对于任意一条从左上到右下的路径,一定是前面一段是0,后面一段是1。(显然)
于是对于每一个0,1交界点都要付出一定代价,所以直接建图最小割就好了。
于是网络流愉快的T了。
因为是平面图,所以转对偶图跑最短路就行了。
原来dij比spfa快那么多的啊
code:(AC)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#define LL long long
#define pa pair<long long,long long>
using namespace std;
queue<int> q;
LL n,map[510][510][4];const LL inf=1<<29;
struct node{
    LL y,c,next;
}a[6400000];LL last[600010],len=0,dis[600010];
bool v[600010];
LL st,ed;
LL read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void ins(LL x,LL y,LL c)
{
    a[++len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
}
LL qs(LL x,LL y)
{
    if(x>n||y<=1) return ed;
    if(x<=1||y>n) return st;
    x--;y--;return (x-1)*(n-1)+y;
}
int main()
{
    n=read();n++;
    memset(map,-1,sizeof(map));
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<n;j++) map[i][j][0]=read();
    for(LL i=1;i<n;i++)
        for(LL j=1;j<=n;j++) map[i][j][1]=read();
    for(LL i=1;i<=n;i++)
        for(LL j=2;j<=n;j++) map[i][j][2]=read();
    for(LL i=2;i<=n;i++)
        for(LL j=1;j<=n;j++) map[i][j][3]=read();
    st=0;ed=n*n+1;
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<=n;j++)
        {
            if(j+1<=n) ins(qs(i,j+1),qs(i+1,j+1),map[i][j][0]);
            if(i+1<=n) ins(qs(i+1,j+1),qs(i+1,j),map[i][j][1]);
            if(j-1>=1) ins(qs(i+1,j),qs(i,j),map[i][j][2]);
            if(i-1>=1) ins(qs(i,j),qs(i,j+1),map[i][j][3]);
        }
    memset(dis,63,sizeof(dis));
    memset(v,false,sizeof(v));
    priority_queue<pa,vector<pa>,greater<pa> >q;
    memset(dis,127,sizeof(dis));dis[st]=0LL;
    memset(v,false,sizeof(v));
    q.push(make_pair(0,st));
    while(!q.empty())
    {
        int x=q.top().second;q.pop();
        if(v[x]) continue;
        v[x]=true;
        for(int i=last[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(dis[y]>dis[x]+a[i].c)
            {
                dis[y]=dis[x]+a[i].c;
                q.push(make_pair(dis[y],y));
            }
        }
    }
    printf("%lld",dis[ed]);
}

code:(TLE)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
LL n,map[510][510][4];const LL inf=1<<29;
struct node{
    LL x,y,next,c,other;
}a[6400000];LL last[500010],len=0;
LL h[500010],s[500010],st,ed;
void ins(LL x,LL y,LL c)
{
    //printf("%lld->%lld %lld\n",x,y,c);
    LL k1=++len;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
    LL k2=++len;
    a[len].x=y;a[len].y=x;a[len].c=0;
    a[len].next=last[y];last[y]=len;
    a[k1].other=k2;a[k2].other=k1;
}
bool bt_h()
{
    memset(h,0,sizeof(h));
    LL l=1,r=2;s[l]=st;h[st]=1;
    while(l!=r)
    {
        LL x=s[l];
        for(LL i=last[x];i;i=a[i].next)
        {
            LL y=a[i].y;
            if(h[y]==0&&a[i].c>0) h[y]=h[x]+1,s[r++]=y;
        }
        l++;
    }
    return h[ed]!=0;
}
LL findflow(LL x,LL f)
{
    if(x==ed) return f;
    LL t,ans=0;
    for(LL i=last[x];i;i=a[i].next)
    {
        LL y=a[i].y;
        if(h[x]+1==h[y]&&a[i].c>0&&ans<f)
        {
            ans+=(t=findflow(y,min(a[i].c,f-ans)));
            a[i].c-=t;a[a[i].other].c+=t;
        }
    }
    if(ans==0) h[x]=0;
    return ans;
}
LL qs(LL x,LL y) {return (x-1)*n+y;}
int main()
{
    scanf("%lld",&n);n++;
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<n;j++) scanf("%lld",&map[i][j][0]);
    for(LL i=1;i<n;i++)
        for(LL j=1;j<=n;j++) scanf("%lld",&map[i][j][1]);
    for(LL i=1;i<=n;i++)
        for(LL j=2;j<=n;j++) scanf("%lld",&map[i][j][2]);
    for(LL i=2;i<=n;i++)
        for(LL j=1;j<=n;j++) scanf("%lld",&map[i][j][3]);
    st=1;ed=qs(n,n);
    for(LL i=1;i<=n;i++)
        for(LL j=1;j<=n;j++)
        {
            //printf("now:%lld %lld\n",i,j);
            if(j+1<=n) ins(qs(i,j),qs(i,j+1),map[i][j][0]);
            if(i+1<=n) ins(qs(i,j),qs(i+1,j),map[i][j][1]);
            if(j-1>=1) ins(qs(i,j),qs(i,j-1),map[i][j][2]);
            if(i-1>=1) ins(qs(i,j),qs(i-1,j),map[i][j][3]);
        }
    LL ans=0;
    while(bt_h()) ans+=(LL)findflow(st,inf);
    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值