BZOJ 3504

这题是网络流最大流。
如果有两点之间是危桥,则连一条流量为2的边,不然流量为∞。然后再取一点S(权且称为0号点)为源点与a1,b1连一条流量为∞的边,点T(权且称为N+1号点)为汇点与a2,b2连一条流量为∞的边,跑一边最大流(Dinic或EK等等)。
但这并未结束,可能出现a1流到b2,但b1未流到的情况。所以换一下b1,b2的位置(即S向b2连边,b1向T连边),再跑一遍最大流,两次都符合条件的则输出Yes,不然输No即可。


晒一下代码(Dinic算法):

/**************************************************************
    Problem: 3504
    User: fantasticwtl
    Language: C++
    Result: 正确
    Time:48 ms
    Memory:884 kb
****************************************************************/

#include 
#include 
#include 
#include 
using namespace std;
int d[101],g[101][101],q[101],gg[101][101],n,a1,a2,b1,b2,an,bn;
char c,enter;
bool jz ()
{
    memset(d,0,sizeof(d));
    d[0]=1;q[1]=0;
    int h=0,t=1;
    while(hfor(int i=0;i<=n;i++)
         if(d[i]==0&&g[q[h]][i]){
             t++;d[i]=d[q[h]]+1;q[t]=i;
         }
        if(d[n])return 1;
    }
    if(d[n]==0)return 0;else return 1;
}
int find (int x,int y)
{
    if(x>=n)return y;
    int a=0;
    for(int i=0;i<=n;i++)
     if(d[i]==d[x]+1&&g[x][i]>0&&(a=find(i,min(y,g[x][i])))){g[x][i]-=a;g[i][x]+=a;return a;}
    return 0;
}
int main ()
{
while(scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF){
        bool ff=0;
        memset(g,0,sizeof(g));memset(gg,0,sizeof(gg));
        a1++;a2++;b1++;b2++;
        for(int i=1;i<=n;i++){
          scanf("%c",&enter);//处理换行
          for(int j=1;j<=n;j++){
             scanf("%c",&c);
             if(i>j){
                 if(c=='O')g[j][i]=gg[j][i]=g[i][j]=gg[i][j]=2;//危桥
                 if(c=='N')g[j][i]=gg[j][i]=g[i][j]=gg[i][j]=100000000;//非危桥
             }
          }
        }//读入部分
        n++;
        g[0][a1]=2*an+1;g[0][b1]=2*bn+1;g[a2][n]=2*an+1;g[b2][n]=2*bn+1;
        int q=0;
        while(jz ())q+=find (0,1000000000);//第一次Dinic
        if(q<2*(an+bn))ff=1;
        if(!ff){//如果满足第一次才做第二次
            memset(g,0,sizeof(g));
            for(int i=1;i<=n-1;i++)
             for(int j=1;j<=n-1;j++)g[i][j]=gg[i][j];
            g[0][a1]=2*an+1;g[0][b2]=2*bn+1;g[a2][n]=2*an+1;g[b1][n]=2*bn+1;
            int q=0,w=0;
            while(jz())if(w=(find(0,100000000)))q+=w;//第二次Dinic
            if(q<2*(an+bn))ff=1;
        }
        if(ff)printf("No\n");else printf("Yes\n");
    }
}

多消化消化最大流,明天开始做最小费用最大流。

你可能感兴趣的:(BZOJ)