首页 > 其他 > 详细

BZOJ 3504: [Cqoi2014]危桥 [最大流]

时间:2017-01-01 20:40:20      阅读:256      评论:0      收藏:0      [点我收藏+]

3504: [Cqoi2014]危桥

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1407  Solved: 703
[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

双向图,往返=走好几次--流量
危桥c=2,普通c=INF
s--an-->a1   a2--an-->t
  --bn-->b1  b2--bn-->t
看是否满流即可
但是有个问题,a1的流量可能流到b2,同时b1的到a2
 
于是,交换b1和b2的位置,再做一遍最大流看是否满流,满流则可行
为什么呢?
linkct讲课说,两个流f1和f2可行,|f1+f2|/2也可行(平均都小于每一个)
证明具体忘了,自己又想了一下,不一定对
考虑前后两次流,
第一次:f1
a1-->a2  an-x
b1-->b2  an-x
a1-->b2 x
a2-->b1 x
第二次:f2
a1-->a2  an-x
b2-->b1  an-x
a1-->b1  x
b2-->a2  x
相加|f1+f2|/2:  f(a1,a2)=an-x  f(b1,b2)=0  f(a1,a2)=x  所以f(a1,a2)=an
 
实现上的问题:
1.老老实实的重构图
2.老老实实的保存边容量 g[i][j]=0!!!
3.双向图反向边c=c就行了
4.+1 *2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=55,INF=1e9;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1; c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0; c=getchar();}
    return x*f;
}
int n,a1,a2,an,b1,b2,bn,s,t;
int g[N][N];
int tot;
char ss[N];
struct edge{
    int v,ne,c,f;
}e[N*N<<1];
int cnt,h[N];
inline void ins(int u,int v,int c){
    cnt++;
    e[cnt].v=v;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[u];h[u]=cnt;
    cnt++;
    e[cnt].v=u;e[cnt].c=c;e[cnt].f=0;e[cnt].ne=h[v];h[v]=cnt;
}
int q[N],head,tail,vis[N],d[N];
bool bfs(){
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    head=tail=1;
    q[tail++]=s;d[s]=0;vis[s]=1;
    while(head!=tail){
        int u=q[head++];
        for(int i=h[u];i;i=e[i].ne){
            int v=e[i].v;
            if(!vis[v]&&e[i].c>e[i].f){
                vis[v]=1;
                d[v]=d[u]+1;
                if(v==t) return true;
                q[tail++]=v;
            }
        }
    }
    return false;
}

int cur[N];
int dfs(int u,int a){
    if(u==t||a==0) return a;
    int flow=0,f;
    for(int &i=cur[u];i;i=e[i].ne){
        int v=e[i].v;
        if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c-e[i].f)))>0){
            flow+=f;
            e[i].f+=f;
            e[((i-1)^1)+1].f-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int dinic(){
    int flow=0;
    while(bfs()){
        for(int i=s;i<=t;i++) cur[i]=h[i];
        flow+=dfs(s,INF);
    }
    return flow;
}
int th[N],tc;
bool solve(){
    s=0;t=n+1;
    ins(s,a1,an);ins(s,b1,bn);
    ins(a2,t,an);ins(b2,t,bn);
    int ans=dinic();//printf("ans1 %d\n",ans);
    if(ans!=an+bn) return false;
    
    cnt=0;memset(h,0,sizeof(h));
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++) if(g[i][j]) ins(i,j,g[i][j]);
    
    ins(s,a1,an);ins(s,b2,bn);
    ins(a2,t,an);ins(b1,t,bn);
    ans=dinic();//printf("ans2 %d\n",ans);
    if(ans!=an+bn) return false;
    return true;
}
int main(){
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        a1=read()+1;a2=read()+1;an=read()*2;
        b1=read()+1;b2=read()+1;bn=read()*2;
        cnt=0;memset(h,0,sizeof(h));
        for(int i=1;i<=n;i++){
            scanf("%s",ss+1);
            for(int j=i+1;j<=n;j++){
                if(ss[j]==O) ins(i,j,2),g[i][j]=2;
                else if(ss[j]==N) ins(i,j,INF),g[i][j]=INF;
                else g[i][j]=0;
            }
        }
        if(solve()) puts("Yes");
        else puts("No");
    }
}

 

 

BZOJ 3504: [Cqoi2014]危桥 [最大流]

原文:http://www.cnblogs.com/candy99/p/6241419.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!