原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3504
题意:
Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?
数据范围
4<=N<50
O<=a1, a2, b1, b2<=N-1
1 <=an. b<=50
题解:
很容易想到网络流,最容易想的建边方式是:
危桥:双向各一条容量为1的边(当然还各有反边,共四条边)
普通桥:双向各一条容量为inf的边
S到a1给an的流量,S到b1给bn的流量,a2->T,b2->T,看是否满流。
但是这样有两个问题:
1、b1与a2相通,那么b1的流入就可以不通过b2到达T,而是通过走a2到达T。
2、同一个危桥,a1->a2与b1->b2走这座桥是不同方向的,而正反流量都是1,那么两次往返都可能会走到这座桥,就是4次,但不会被判出来。
而解决这些问题的办法:
交换b1,b2再跑一次。
即,把S连向b2,b1连向T再跑一次。要两次都合法才算合法。
方向变了解决了问题二,而对于问题一:
如果 b2仍然可以”绕路”,那么b1,b2都可绕到a2的路相连就成了一条路,
因此两次都合法就合法了
代码:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
queue<int> Q;
const int N=55;
const int inf=10000;
int S,T,n,head[N],to[4*N*N],nxt[4*N*N],w[4*N*N],a1,a2,an,b1,b2,bn,num,dep[N];
bool vis[N];
char s[N][N];
void build(int u,int v,int ww)
{
num++;
to[num]=v;
nxt[num]=head[u];
w[num]=ww;
head[u]=num;
num++;
to[num]=u;
nxt[num]=head[v];
w[num]=0;
head[v]=num;
}
void init(int opt)
{
memset(head,0,sizeof(head)); num=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(s[i][j]=='O') build(i,j,1);
else if(s[i][j]=='N') build(i,j,inf);
}
}
build(S,a1,an);build(a2,T,inf);
if(opt==1) {build(S,b1,bn); build(b2,T,inf);}
else {build(S,b2,bn); build(b1,T,inf);}
}
bool bfs()
{
while(!Q.empty()) Q.pop();
memset(vis,0,sizeof(vis));
memset(dep,0,sizeof(dep));
vis[S]=1; dep[S]=1; Q.push(S);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(vis[v]||w[i]<=0) continue;
dep[v]=dep[u]+1; vis[v]=1;
Q.push(v);
}
}
return vis[T];
}
int dfs(int u,int d)
{
if(!d||u==T) return d;
int ret=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dep[v]!=dep[u]+1||w[i]<=0) continue;
int flow=dfs(v,min(d,w[i]));
ret+=flow;
d-=flow;
w[i]-=flow;
w[i^1]+=flow;
}
if(ret==0) dep[u]=-1;
return ret;
}
bool check()
{
int ret=0;
while(bfs())
{
ret+=dfs(S,inf);
}
return ret>=an+bn;
}
int main()
{
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF)
{
a1++; a2++; b1++;b2++; S=n+1; T=n+2;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
bool flag=1;
for(int opt=1;opt<=2;opt++)
{
init(opt);
if(!check()) flag=0;
}
if(!flag) printf("No\n");
else printf("Yes\n");
}
return 0;
}