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
#include
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 xint 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;ifor(int j=0;jif(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;
}

其他题处理

#include
#include
#include
#include
#include
#include
#define mm1(a) memset((a),-1,sizeof((a)))  
#define mm0(a) memset((a),0,sizeof((a)))  
#define mmx(a) memset((a),0x3f,sizeof((a)))  
using namespace std;
typedef long long LL;
const int N = 100005;
const int INF = 0x3f3f3f3f;
int n,m,tot,vt,vs;
int d[N],head[N];
std::vector<int> v[N];
set<int>have;
int numm[N];
char tools[10000];
struct lp{
    int to,w,nex;
    lp(){}
    lp(int a,int b,int c){to=a;w=b;nex=c;}
}cw[N<<2];
int pigNum[N],pigTo[N];
inline void add(int a,int b,int c){
    cw[++tot]=lp(b,c,head[a]);
    head[a]=tot;
    cw[++tot]=lp(a,0,head[b]);
    head[b]=tot;
}
bool bfs(){
    mm1(d);
    queue<int>Q;
    Q.push(vt);d[vt]=0;
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        for(int i=head[u];i!=-1;i=cw[i].nex){
            int v=cw[i].to;
            if(cw[i^1].w&&d[v]==-1){
                d[v]=d[u]+1;
                Q.push(v);
            }
        }
    }
    return d[vs]!=-1;
}
int dfs(int x,int f){
    if(x==vt||f==0) return f;
    int use=0,w;
    for(int i=head[x];i!=-1;i=cw[i].nex){
        int to=cw[i].to;
        if(d[to]==d[x]-1 && cw[i].w){
            w=dfs(to,min(cw[i].w,f-use));
            cw[i].w-=w,cw[i^1].w+=w;
            use+=w;
            if(use==f) return f;
        }
    }
    return use;
}
inline void init(){
    tot=-1;
    mm1(head);
    vs=0,vt=n+m+1;
}
/*
1:Dinic最后一次的bfs
2:通过删除仪器与T的边判断仪器,再判断实验
3:如果原向边和残留都是0则不要。若正向边或反向边大于0则要
*/
int main(){
    scanf("%d%d",&m,&n);
    init();
    int sum=0;
    for(int i=1; i<=m; i++) {
        memset(tools,0,sizeof(tools));
        int ulen=0,tool;
        scanf("%d",&tool);
        numm[i]=tool;
        sum+=tool;
        add(vs,i,tool);
        cin.getline(tools,10000);
        while(sscanf(tools+ulen,"%d",&tool)==1){
            add(i,tool+m,INF);
            v[i].push_back(tool);
            if(tool==0)ulen++;
            else {
                while(tool){
                    tool/=10;
                    ulen++;
                }
            }
            ulen++;
        }
    }
    for(int i=1,x;i<=n;++i){
        scanf("%d",&x);
        add(i+m,vt,x);
    }
    int have_num=0,tmpans=0;
    while(bfs())tmpans+=dfs(vs,INF);
    for(int i=1;i<=m;++i){
        if(d[i]==-1)printf("%d ",i);
    }
    printf("\n");
    for(int i=1;i<=n;++i){
        if(d[i+m]==-1)printf("%d ",i );
    }
    printf("\n");
    printf("%d\n",sum-tmpans);
    return 0;
}

你可能感兴趣的:(网络流,彩蛋,ACM算法之旅)