CSU2073-Tile Cut-中南多校对抗赛-网络流-SAP

题意:

1. 直接给你一张图:由W,I,N三个字母构成;
2. 当WIN三个字母成一条直线或成“L”型时,为一种满足的情况;
3. 一个字母只能在一个可满足的情况中,求情况的最大数

思路:

网络流裸题:

初步想法:
1。W向I连一条边,I向N连一条边;
2。设置超级源点S向每个W连边,每个N向超级汇点T连边,跑一遍最大流;
3。问题所在:

  W
W I N
  N

这种情况得出的答案应该是1,但是跑出来的结果却不是,显然有问题。
4。解决方法:
拆点:
将 I 点拆成点 I1 和点 I2,两个点的流量设为1,这样跑一边最大流就行了

题目链接:

题目链接

AC代码:
(吐槽一句:这个题的输入输出真恶心)

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int MX=5005;
const LL inf=1e17;
LL ans;
int fr[MX],h[MX],nh[MX];
int s,t,e,n,m;
char ss[MX][MX];
int dir[4][2]={1,0,-1,0,0,1,0,-1};
struct lp
{
    int t,ne;
    LL w;
}a[MX*100];
void ins(int f,int t,LL w)
{
    a[++e].t=t,a[e].ne=fr[f],fr[f]=e,a[e].w=w;
    a[++e].t=f,a[e].ne=fr[t],fr[t]=e,a[e].w=0;
}
LL Min(LL x,LL y)
{
    return x<y?x:y;
}
LL sap(int u,LL fl)
{
    if (u==t) return fl;
    LL res=fl;
    for (int i=fr[u];i;i=a[i].ne){
        if (a[i].w&&h[a[i].t]+1==h[u]){
            LL t=sap(a[i].t,Min(res,a[i].w));
            a[i].w-=t,a[i^1].w+=t;
            if (!(res-=t)) return fl;
        }
    }
    if (!(--nh[h[u]])) h[t]=t;
    ++nh[++h[u]];
    return fl-res;
}
int main()
{
    while(1){
        int flag=1;
        n=0;
        while(gets(ss[n])){
            n++;
            if(!ss[n-1][0]){
                n--;flag=0;
                break;
            }
        }
        m=strlen(ss[0]);
        //printf("*%d %d\n",n,m );
        memset(fr,0,sizeof(fr));
        memset(nh,0,sizeof(nh));
        memset(h,0,sizeof(h));
        s=1;t=2+n*m*2;ans=0;e=1;
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                if(ss[i][j]=='I'){
                    ins(i*m+j+1+1,i*m+j+1+n*m+1,1LL);
                    for(int h=0;h<4;++h){
                        int px=i+dir[h][0],py=j+dir[h][1];
                        if(px<0||py<0||px>=n||py>=m)continue;
                        if(ss[px][py]=='W')ins(1+px*m+py+1,1+i*m+j+1,1LL);
                        if(ss[px][py]=='N')ins(n*m+1+i*m+j+1,1+px*m+py+1,1LL);
                    }
                }
                if(ss[i][j]=='W')ins(1,i*m+j+1+1,1LL);
                if(ss[i][j]=='N')ins(i*m+j+1+1,t,1LL);
            }
        }
        nh[0]=t;
        while (h[t]!=t){ 
            ans+=sap(s,inf);
        }
        printf("%lld\n",ans);
        if(flag)break;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/80018946