题意:链接
方法:最大流
解析:这道题其实第一眼看上去是(和谐)题,然后发现水水的写完后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的一条路
得证
于是乎按照这个思路再跑一遍最大流就行了。
代码:
优于观测数据以及其他不可抗力原因,我的代码及其丑陋,所以他人的正常代码和我的解题思路更配哦- -
using 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");
}
}