BZOJ 3504 [Cqoi2014] 危桥 最大流

来源:互联网 发布:mac 批量保存网页图片 编辑:程序博客网 时间:2024/04/20 03:20

题意:链接

方法:最大流

解析:这道题其实第一眼看上去是(和谐)题,然后发现水水的写完后WA了,然后从网上下来数据来观测数据,发现自己WA的地方都是同一个地方,之后上网上看了看其他人的姿势,算是懂了这道题吧。

首先读完题后,第一眼被这个往返卡了一会,后来发现,假如说从A到B,AB间是危桥的话,那你顶多在其中往返一次,也就是对应流量为1,如此的话,因为无向,所以B到A也必然有流量为1的一条路,在加上点细节修饰以及自己手画个图就能明白。

接下来我就以为这道题已经完事了,直接写了发最大流一跑发现WA了!

后经我亲测数据发现有的时候的流量并非自己所希望的从a1流向a2,有的满流的情况居然是从a1流到b2,这样怎么搞?

然后题解里给出了种办法,就是跑完第一次最大流后如果是满流则重新建图,其中桥的部分不变,源点到a1,a2到汇点的部分不变,只需要把原来的源点到b1,b2到汇点改为源点到b2,b1到汇点即可,再次判断,如果这样跑出来还是满流的话,就有解。

不过遗憾的是我并没有找到证明,所以就自己写了个证明,不知其严谨性。

第一次满流后

假设a1->a2 流量为 an-x

a1->b2 流量为 x

b1->a2 流量为 x

b1->b2 流量为 bn-x

之后我们假设第二次跑完之后又达到满流。

则a1->a2 流量仍为 an-x

∴a1->b1 流量为 x

b2->a2 流量为 x

b2->b1 流量为bn-x

又先前a1->b2 流量为x

∴a1->b2->b1流量为x(无向图)

则b2->b1又可有流量为x的一条路

又b2->b1已有流量为bn-x的一条路

∴b2->b1有流量为bn的一条路

则a1->a2有流量为an的一条路

得证

于是乎按照这个思路再跑一遍最大流就行了。

代码:

优于观测数据以及其他不可抗力原因,我的代码及其丑陋,所以他人的正常代码和我的解题思路更配哦- -

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 2700#define INF 0x3f3f3f3fusing namespace std;struct node {    int to,val,next;}edge[N*N];int head[N],dep[N],map[N][N];int n,a1,a2,an,b1,b2,bn,cnt;char s[N];void init(){    memset(head,-1,sizeof(head));cnt=0;}void edgeadd(int from,int to,int val){    edge[cnt].to=to;    edge[cnt].val=val;    edge[cnt].next=head[from];    head[from]=cnt++;}int bfs(int s,int e){    memset(dep,0,sizeof(dep));    queue<int>q;    q.push(s);    dep[s]=1;    while(!q.empty())    {        int u=q.front();        if(u==e)return 1;        q.pop();        for(int i=head[u];i!=-1;i=edge[i].next)        {            int to=edge[i].to;            if(edge[i].val==0||dep[to]!=0)continue;            dep[to]=dep[u]+1;            q.push(to);        }    }    return 0;}int dfs(int s,int max_vale){    int ret=0,tmp;    if(s==n*n+1)return max_vale;    for(int i=head[s];i!=-1;i=edge[i].next)    {        int to=edge[i].to;        if(edge[i].val==0||dep[to]!=dep[s]+1)continue;        tmp=dfs(to,min(max_vale-ret,edge[i].val));        edge[i].val-=tmp;        edge[i^1].val+=tmp;        ret+=tmp;        if(ret==max_vale)return ret;    }    return ret;}void build(){    init();    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++)        {            if(map[i][j]==1)            {                edgeadd(i,j,INF);                edgeadd(j,i,0);            }else if(map[i][j]==2)            {                edgeadd(i,j,1);                edgeadd(j,i,0);            }        }    }}int main(){//  freopen("bridge.in","r",stdin);//  freopen("bridge.out","w",stdout);    while(~scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn))    {        memset(map,0,sizeof(map));        init();        a1++,a2++,b1++,b2++;        for(int i=1;i<=n;i++)        {            scanf("%s",s);            for(int j=0;j<n;j++)            {                if(s[j]=='N')                {                    map[i][j+1]=1;                }else if(s[j]=='O')                {                    map[i][j+1]=2;                }            }        }        build();        edgeadd(0,a1,1*an);        edgeadd(a1,0,0);        edgeadd(a2,n*n+1,1*an);        edgeadd(n*n+1,a2,0);        edgeadd(0,b1,1*bn);        edgeadd(b1,0,0);        edgeadd(b2,n*n+1,1*bn);        edgeadd(n*n+1,b2,0);         int ret=0,flag=0;        while(bfs(0,n*n+1))        {            while(int t=dfs(0,INF))            {                ret+=t;            }        }        if(ret<1*(an+bn)){flag=1;}        if(!flag)        {            build();            edgeadd(0,a1,1*an);            edgeadd(a1,0,0);            edgeadd(a2,n*n+1,1*an);            edgeadd(n*n+1,a2,0);            edgeadd(0,b2,1*bn);            edgeadd(b2,0,0);            edgeadd(b1,n*n+1,1*bn);            edgeadd(n*n+1,b1,0);             ret=0;            while(bfs(0,n*n+1))            {                while(int t=dfs(0,INF))                {                    ret+=t;                }            }            if(ret<1*(an+bn)){flag=1;}        }        if(flag)printf("No\n");        else printf("Yes\n");    }}
1 0