http://www.lydsy.com/JudgeOnline/problem.php?id=3504
往返n遍,即单向2*n遍
危桥流量为2,普通桥流量为inf
原图跑一遍最大流
交换b1,b2再跑一遍最大流
如果两次的结果都等于(an+bn)*2
则可以
证明参见http://www.cnblogs.com/chenyushuo/p/5139556.html
#include<queue> #include<cstdio> #include<cstring> #include<iostream> using namespace std; #define N 100 #define M 3000 const int inf=1e9; int n,a1,a2,an,b1,b2,bn; char s[51][51]; int tot; int front[N],nxt[M<<1],to[M<<1],val[M<<1],from[M<<1]; int lev[N],num[N]; int path[N]; int cur[N]; int src,decc; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); } } void add(int u,int v,int w) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0; } void build() { tot=1; memset(front,0,sizeof(front)); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { if(s[i][j]==‘O‘) add(i,j,2); else if(s[i][j]==‘N‘) add(i,j,inf); } src=0; decc=n+1; add(src,a1,an<<1); add(a2,decc,an<<1); add(src,b1,bn<<1); add(b2,decc,bn<<1); } bool bfs() { queue<int>q; for(int i=src;i<=decc;++i) lev[i]=decc+1; q.push(decc); lev[decc]=0; int now,t; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) { t=to[i]; if(lev[t]==decc+1 && val[i^1]) { lev[t]=lev[now]+1; q.push(t); } } } return lev[src]!=decc+1; } int augment() { int now=decc,flow=inf; int i; while(now!=src) { i=path[now]; flow=min(flow,val[i]); now=from[i]; } now=decc; while(now!=src) { i=path[now]; val[i]-=flow; val[i^1]+=flow; now=from[i]; } return flow; } int isap() { int flow=0; if(!bfs()) return 0; memset(num,0,sizeof(num)); for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i]; int now=src,t; while(lev[src]<=decc) { if(now==decc) { flow+=augment(); now=src; } bool advanced=false; for(int i=cur[now];i;i=nxt[i]) { t=to[i]; if(lev[t]==lev[now]-1 && val[i]) { advanced=true; path[t]=i; cur[now]=i; now=t; break; } } if(!advanced) { int mi=decc; for(int i=front[now];i;i=nxt[i]) if(val[i]) mi=min(mi,lev[to[i]]); if(!--num[lev[now]]) break; num[lev[now]=mi+1]++; cur[now]=front[now]; if(now!=src) now=from[path[now]]; } } return flow; } int main() { int A,B; while(scanf("%d",&n)!=EOF) { read(a1); read(a2); read(an); a1++; a2++; read(b1); read(b2); read(bn); b1++; b2++; for(int i=1;i<=n;++i) scanf("%s",s[i]+1); build(); A=isap(); if(A!=(an+bn)*2) { puts("No"); continue; } swap(b1,b2); build(); B=isap(); puts(A==B ? "Yes" : "No"); } }
3504: [Cqoi2014]危桥
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1739 Solved: 868
[Submit][Status][Discuss]
Description
Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双
向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?
Input
本题有多组测试数据。
每组数据第一行包含7个空格隔开的整数,分别为N、al、a2、an、bl、b2、bn。
接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i一1和j-l的岛屿间的连接情况,若为“O”则表示有危桥相连:为“N”表示有普通的桥相连:为“X”表示没有桥相连。
|
Output
对于每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。
Sample Input
4 0 1 1 2 3 1
XOXX
OXOX
XOXO
XXOX
4 0 2 1 1 3 2
XNXO
NXOX
XOXO
OXOX
Sample Output
Yes
No
数据范围
4<=N<50
O<=a1, a2, b1, b2<=N-1
1 <=an. b<=50