• 网络流24题


    T1 飞行员配对方案

    二分图最大匹配。这里写个匈牙利算法

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=105;
    struct edge{
        int x,y,next;
        edge(){}
        edge(int _x,int _y,int _nt):x(_x),y(_y),next(_nt){}
    }e[20005];
    int head[maxn],tot=0;
    #define addedge(x,y) {
        e[++tot]=edge(x,y,head[x]);head[x]=tot;
    }
    int n,m;
    bool vst[maxn];
    int match[maxn];
    int DFS(int x){
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y;
            if(vst[y])continue;vst[y]=1;
            if(!match[y] || DFS(match[y])){
                match[y]=x;
                return 1;
            }
        }
        return 0;
    }
    int main(){
        scanf("%d%d",&n,&m);
        int x,y;
        while(cin>>x>>y && x+y>0)addedge(x,y);
    
        int ans=0;
        for(int i=1;i<=n;i++){
            memset(vst,0,sizeof(vst));
            ans+=DFS(i);
        }
        printf("%d
    ",ans);
    }

    T2 太空飞行计划

    最大权闭合子图
    S向实验i连一条流量为Ci的边。仪器i向T连一条流量为Ci的边,每组实验i与仪器j的关系连一条流量为INF的边
    答案为全部实验的收入的和减去网络最大流(最小割)
    细致考虑割掉了一些什么样的边

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    const int maxn=110;
    const int maxm=10010;
    const int INF=0x3f3f3f3f;
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int _x,int a,int b,int c):x(_x),y(a),next(b),v(c){}
    } e[maxm<<1];
    int head[maxn],tot=1,h[maxn],cur[maxn];
    int n,m,S,T;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    bool BFS(){
        queue<int>q;
        for(int i=1;i<=T;i++)h[i]=-1;
    
        h[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;int v=e[i].v;
                if(h[y]==-1 && v){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        int tmp,used=0;
        if(x==T)return f;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y,v=e[i].v;
            if(h[y]==h[x]+1 && v){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;if(e[i].v)cur[x]=i;
                e[i^1].v+=tmp;
                used+=tmp;
                if(used==f)return used;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int maxf(){
        int ret=0;
        while(BFS()){
            for(int i=1;i<=T;i++)cur[i]=head[i];
    
            ret+=DFS(S,INF);
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&n,&m);
        S=n+m+1,T=S+1;
        int ans=0;
        for(int i=1;i<=n;i++){
            int c;
            scanf("%d",&c);
            addedge(S,i,c);
            ans+=c;
            int d;
            while(scanf("%d",&d)&&(d!=0)){
                addedge(i,d+n,INF);
            }
        }
        for(int i=1;i<=m;i++){
            int c;
            scanf("%d",&c);
            addedge(i+n,T,c);
        }
    
    
    
        ans-=maxf();
        for(int i=1;i<=n;i++)if(h[i]!=-1)cout<<i<<" ";cout<<endl;
        for(int i=1;i<=m;i++)
            if(h[i+n]!=-1)cout<<i<<" ";cout<<endl;
        cout<<ans<<endl;
    }

    T3 最小路径覆盖

    求有向无环图最小路径覆盖
    拆点构造二分图,原图中每一个点i拆成二分图X,Y集合中的两个点Xi,Yi。对于原图中的每条边(i,j),在二分图中连边(Xi,Yi)。最小路径覆盖条数等于原图点数减去最大匹配数。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    const int maxn=40010;
    const int maxm=80010;
    const int INF=0x3f3f3f3f;
    struct edge{
        int y,next,v;
        edge(){}
        edge(int a,int b,int c):y(a),next(b),v(c){}
    } e[maxm<<1];
    
    int head[maxn],tot=1;
    int n,m,S,T;
    void addedge(int x,int y,int v){
        e[++tot]=edge(y,head[x],v);head[x]=tot;
        e[++tot]=edge(x,head[y],0);head[y]=tot;
    }
    int cur[maxn],h[maxn];
    
    #include<queue>
    queue<int>q;
    bool BFS(){
        memset(h,-1,sizeof(h));
        q.push(S);h[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y,v=e[i].v;
                if(h[y]==-1 && v){
                    q.push(y);
                    h[y]=h[x]+1;
                }
            }
        }
        return h[T]!=-1;
    }
    int mark[maxn],to[maxn];
    int DFS(int x,int f){
        if(x==T)return f;
        int tmp,used=0;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(v && h[y]==h[x]+1){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(tmp){
                    to[x]=y;
                    if(y>n)mark[y-n]=1;
                }
                if(e[i].v)cur[x]=i;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int maxf(){
        int ret=0;
        while(BFS()){
            for(int i=1;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&n,&m);
    
        S=n*2+1;T=S+1;
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            addedge(x,y+n,1);
        }
        for(int i=1;i<=n;i++){
            addedge(S,i,1);
            addedge(i+n,T,1);
        }
        memset(to,0,sizeof(to));
        memset(mark,0,sizeof(mark));
        printf("%d
    ",n-maxf());
        for(int i=1;i<=n;i++){
            if(mark[i])continue;
            printf("%d",i);
            int y=i;
            while(to[y]){
                printf(" %d",to[y]-n);
                y=to[y]-n;
            }
            printf(" 0
    ");
        }
    }

    T4 魔术球问题

    枚举答案+最小路径覆盖

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    using namespace std;
    const int maxn=4010;
    const int maxm=200010;
    const int INF=0x3f3f3f3f;
    const int offset=2000;
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int _x,int a,int b,int c):x(_x),y(a),next(b),v(c){}
    } e[maxm<<1];
    
    int head[maxn],tot=1;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    bool issquare[maxn];
    int S,T,n;
    #include<queue>
    queue<int>q;
    int h[maxn];
    bool BFS(){
        memset(h,-1,sizeof(h));
        h[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                if(v && h[y]==-1){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(v && h[y]==h[x]+1){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int ret=0;
    int maxf(){
    
        while(BFS())ret+=DFS(S,INF);
        return ret;
    }
    int main(){
        scanf("%d",&n);
        memset(issquare,0,sizeof(issquare));
        for(int i=1;i<=60;i++)issquare[i*i]=1;
        S=0;T=maxn-1;
        addedge(S,1,1);
        addedge(1+offset,T,1);
        int tmp,A;
        for(A=1;A-maxf() <= n;){
            ++A;
            addedge(S,A,1);
            addedge(A+offset,T,1);
            for(int j=1;j<A;j++){
                if(issquare[A+j])
                    addedge(j,A+offset,1);
            }
        }
        int ANS=A-1;
        printf("%d
    ",ANS);
    }

    T5 圆桌问题

    二分图多重匹配

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cstdlib>
    using namespace std;
    const int maxn=2010;
    const int maxm=400010;
    const int INF=0x3f3f3f3f;
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int _x,int _y,int _nt,int _v):
            x(_x),y(_y),next(_nt),v(_v){}
    } e[maxm];
    int head[maxn],tot=1;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    int cur[maxn],h[maxn];
    int n,m;
    int a[maxn],b[maxn];
    int S,T;
    queue<int>q;
    bool BFS(){
        memset(h,-1,sizeof(h));
        q.push(S);h[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                if( v && h[y]==-1){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(v && h[y]==h[x]+1){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(e[i].v)cur[x]=i;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int maxf(){
        int ret=0;
        while(BFS()){
            for(int i=S;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&n,&m);
        S=0;T=n+m+1;
        int sum=0;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)scanf("%d",&b[i]);
        for(int i=1;i<=n;i++)sum+=a[i];
        for(int i=1;i<=n;i++)
            addedge(S,i,a[i]);
        for(int i=1;i<=m;i++)
            addedge(i+n,T,b[i]);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            addedge(i,n+j,1);
    
        int tmp=maxf();
        if(tmp == sum)puts("1");else puts("0");
    }

    T6 最长递增子序列

    DP+最大流

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cstdlib>
    using namespace std;
    const int maxn=2010;
    const int maxm=400010;
    const int INF=0x3f3f3f3f;
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int a,int b,int c,int d):x(a),y(b),next(c),v(d){}
    }e[maxm];
    int head[maxn],tot=1;
    int S,T;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    int h[maxn],cur[maxn];
    int a[maxn],f[maxn],n;
    
    queue<int>q;
    bool BFS(){
        memset(h,-1,sizeof(h));
        h[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                if(h[y]==-1 && v){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(h[y]==h[x]+1 && v){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(e[i].v)cur[x]=i;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int ret=0;
    int maxf(){
        while(BFS()){
            for(int i=S;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);
        }
        return ret;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            f[i]=1;
        }
        for(int i=n-1;i>=1;i--){
            for(int j=i+1;j<=n;j++)
                if(a[i]<a[j])f[i]=max(f[i],f[j]+1);
        }
        int ans1=0;
        for(int i=1;i<=n;i++)ans1=max(ans1,f[i]);
        printf("%d
    ",ans1);
    
        memset(head,0,sizeof(head));
        tot=1;
        S=0;T=n*2+8;
    
        for(int i=1;i<=n;i++){
            addedge(i,i+n,1);
            if(f[i]==ans1)addedge(S,i,1);
            if(f[i]==1) addedge(i+n,T,1);
            for(int j=i+1;j<=n;j++)
            if(f[i]==f[j]+1 && a[i]<a[j])
                addedge(i+n,j,1);
        }
    
        printf("%d
    ",maxf());
    
        addedge(1,1+n,INF);
        addedge(n,n+n,INF);
        if(f[1]==ans1)addedge(S,1,INF);
        addedge(n+n,T,INF);
    
        printf("%d
    ",maxf());
    }

    T7 试题库问题

    二分图多重匹配

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<queue>
    using namespace std;
    const int maxn=2010;
    const int maxm=400010;
    const int INF=0x3f3f3f3f;
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int a,int b,int c,int d)
            :x(a),y(b),next(c),v(d){}
    } e[maxm];
    int head[maxn],tot=1;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    int S,T;
    int n,m,k;
    int cur[maxn],h[maxn];
    queue<int>q;
    bool BFS(){
        memset(h,-1,sizeof(h));
        h[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                if(v && h[y]==-1){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(v && h[y]==h[x]+1){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(e[i].v)cur[x]=i;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int ret=0;
    int maxf(){
        while(BFS()){
            for(int i=S;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);
        }
        return ret;
    }
    
    int main(){
        scanf("%d%d",&k,&n);
        S=0;T=n+k+1;m=0;
        for(int i=1;i<=k;i++){
            int v;
            scanf("%d",&v);
            m+=v;
            addedge(n+i,T,v);
        }
        for(int i=1;i<=n;i++){
            int p,y;
            addedge(S,i,INF);
            scanf("%d",&p);
            for(int j=1;j<=p;j++){
                scanf("%d",&y);
                addedge(i,y+n,1);
            }
        }
        if(maxf()>=m)puts("YES");
        else puts("No Solution!");
    }

    T9 方格取数问题

    二分图最大点权独立集
    对格子黑白染色。相邻格子连容量正无穷的边。S向白格连流量为格中数值的边,黑格向T连流量为格中数值的边。求最小割,答案为全部格子数值之和减去最小格
    最大点权独立集=点权和-最小点权覆盖集=点权和-最小割集

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    const int maxn=510;
    const int maxm=1000010;
    const int INF=0x3f3f3f3f;
    
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int a,int b,int c,int d)
            :x(a),y(b),next(c),v(d){}
    } e[maxm];
    int head[maxn],tot=1;
    void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    int S,T,n,m;
    int cur[maxn],h[maxn];
    int ret=0;
    queue<int>q;
    bool BFS(){
        memset(h,-1,sizeof(h));
        h[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                if(h[y]==-1 && v){
                    h[y]=h[x]+1;
                    q.push(y);
                }
            }
        }
        return h[T]!=-1;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int i=cur[x];i;i=e[i].next){
            int y=e[i].y;
            int v=e[i].v;
            if(h[y]==h[x]+1 && v){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;
                e[i^1].v+=tmp;
                used+=tmp;
                if(e[i].v)cur[x]=i;
                if(used==f)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int maxf(){
        while(BFS()){
            for(int i=S;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);
        }
        return ret;
    }
    
    const int mx[]={0,1,-1,0};
    const int my[]={1,0,0,-1};
    int num(int x,int y){
        return (x-1)*m+y;
    }
    int main(){
    
        scanf("%d%d",&n,&m);
        S=0;T=n*m+1;
        int sum=0;
    
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            int v;
            scanf("%d",&v);
            sum+=v;
            int id=num(i,j);
            if((i+j)%2==0){
                addedge(S,id,v);
                for(int k=0;k<4;k++){
                    int nx=i+mx[k];
                    int ny=j+my[k];
                    if(nx >=1 && nx<=n && ny>=1 && ny<=m){
                        addedge(id,num(nx,ny),INF);
                    }
                }
            }
            else
                addedge(id,T,v);
        }
        printf("%d
    ",sum-maxf());
    }

    T10 餐巾问题

    供求平衡问题。费用流解决

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int maxn = 2010;
    const int maxm = 4000010;
    const int INF = 0x3f3f3f3f;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c)
            :x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxm];
    int head[maxn],tot=1,dis[maxn],fro[maxn],a[maxn];
    bool inq[maxn];
    int S,T,n,m,p,f,tt,ss;
    void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v,c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    queue<int>q;
    bool SPFA(){
        for(int i=S;i<=T;i++){
            dis[i]=INF;
            inq[i]=0;
        }
        q.push(S);inq[S]=1;
        dis[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            inq[x]=0;
            // cout<<x<<":"<<endl;;
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                // cout<<y<<endl;
                int v=e[i].v;
                int c=e[i].c;
                if(v && dis[x]+c<dis[y]){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;
                        q.push(y);
                    }
                }
            }
        }
        return dis[T]!=INF;
    }
    int mcf(){
        int ret=0;
        while(SPFA()){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x]){
                tmp=min(tmp,e[i].v);
            }
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x]){
                e[i].v-=tmp;
                e[i^1].v+=tmp;
            }
        }
        return ret;
    }
    int main(){
        scanf("%d%d%d%d%d%d",&n,&p,&m,&f,&tt,&ss);
    
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    
        S=0;T=n*2+4;
        for(int i=1;i<=n;i++){
            addedge(S,i,a[i],0);
            addedge(i+n,T,a[i],0);
            addedge(S,i+n,INF,p);
            if(i+1<=n)addedge(i,i+1,INF,0);
            if(i+m<=n)addedge(i,i+m+n,INF,f);
            if(i+tt<=n)addedge(i,i+tt+n,INF,ss);
        }
        printf("%d
    ",mcf());
    
    }
    

    T11 航空路线问题

    最大费用最大流求两条不相交路径
    拆点,每一个城市i拆为Ai和Bi两个点,Ai到Bi连流量为1费用为1的边。A1到B1,An到Bn连流量为2费用为1的边。
    对于给出的边(i,j)。连Bi-Aj流量为1,费用为0。
    求最大费用最大流mcf。若A1-B1、An-Bn满流,则有解为mcf-2,否则无解。

    #include<bits/stdc++.h>
    using namespace std;
    #define MADOKA main
    int hash(char *str){
        int ret=0,seed=131;
        for(;*str;ret=ret*seed+*str++);
        return ret & 0x7fffffff;
    }
    map<int,int>mp;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c):x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[20005];
    int head[105],tot=1,dis[105],fro[105],a[105];
    bool inq[105];
    queue<int>q;
    char str[1000];
    #define addedge(x,y,v,c) {
        e[++tot]=edge(x,y,head[x],v,c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    int S,T,n,m;
    bool SPFA(){
        for(int i=S;i<=T;i++)dis[i]=inq[i]=0;
        q.push(S);inq[S]=1;
        dis[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            inq[x]=0;
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].y;
                int v=e[i].v;
                int c=e[i].c;
                if(v && dis[x]+c>dis[y]){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;q.push(y);
                    }
                }
            }
        }
        return dis[T]!=0;
    }
    int mcf(){
        int ret=0;
        while(SPFA()){
            int tmp=100;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x]){
                e[i].v-=tmp;
                e[i^1].v+=tmp;
            }
        }
        return ret;
    }
    int MADOKA(){
        // freopen("input.txt","r",stdin);
        // freopen("output.txt","w",stdout);
    
        scanf("%d%d",&n,&m);
        S=1;T=n*2;
        for(int i=1;i<=n;i++){
            scanf("%s",str);
            mp[hash(str)]=i;
            if(i==1 || i==n){
                addedge(i,i+n,2,1);
            }else{
                addedge(i,i+n,1,1);
            }
    
        }
        for(int x,y,i=1;i<=m;i++){
            scanf("%s",str);x=mp[hash(str)];
            scanf("%s",str);y=mp[hash(str)];
            if(x==1 && y==n){
                addedge(x+n,y,2,0);continue;
            }
            if(x==n && y==1){
                addedge(y+n,x,2,0);continue;
            }
            if(x < y){
                addedge(x+n,y,1,0);
            }else{
                addedge(y+n,x,1,0);
            }
        }
        int ans=mcf()-2;
        if(e[2].v==0 && e[n<<1].v==0)
            printf("%d
    ",ans);
        else puts("No Solution!");
    
    }

    T13 星际转移问题

    分层图网络流
    太空船为边,以天数分层,从天数为0開始枚举加边求最大流直到最大流达到K为止

    #include<bits/stdc++.h>
    using namespace std;
    #define MADOKA main
    const int maxn = 100005;
    const int INF  = 0x3f3f3f3f;
    int f[maxn];
    int find(int x){return x==f[x]?

    x:f[x]=find(f[x]);} struct edge{ int x,y,next,v; edge(){} edge(int _x,int _y,int _nt,int _v) :x(_x),y(_y),next(_nt),v(_v){} }e[maxn<<1]; int head[maxn],tot=1,n,m,k,S,T,DAY,cur[maxn],h[maxn]; int maxf=0; void addedge(int x,int y,int v){ e[++tot]=edge(x,y,head[x],v);head[x]=tot; e[++tot]=edge(y,x,head[y],0);head[y]=tot; } queue<int>q; bool BFS(){ memset(h,-1,sizeof(h)); q.push(S);h[S]=0; while(!q.empty()){ int x=q.front();q.pop(); for(int y,v,i=head[x];i;i=e[i].next){ y=e[i].y;v=e[i].v; if(v && h[y]==-1){ h[y]=h[x]+1; q.push(y); } } } return h[T]!=-1; } int DFS(int x,int f){ if(x==T)return f; int used=0,tmp; for(int y,v,i=cur[x];i;i=e[i].next){ y=e[i].y;v=e[i].v; if(v && h[y]==h[x]+1){ tmp=DFS(y, min(v,f-used)); e[i].v-=tmp; e[i^1].v+=tmp; used+=tmp; if(e[i].v)cur[x]=i; if(used==f)return f; } } if(!used)h[x]=-1; return used; } void dinic(){ while(BFS()){ for(int i=S;i<=T;i++)cur[i]=head[i]; maxf+=DFS(S,INF); } } struct ship{ int p,r; int s[25]; }p[maxn]; int getnum(int N,int DAY){ return DAY*(n+2)+N; } int MADOKA(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n+2;i++)f[i]=i; S=0;T=20005; for(int i=1;i<=m;i++){ scanf("%d%d",&p[i].p,&p[i].r); int c; for(int j=1;j<=p[i].r;j++){ scanf("%d",&c); if(c== 0)c=n+1; if(c==-1)c=n+2; p[i].s[j]=c; if(j>1){ int x=p[i].s[j-1]; int y=p[i].s[j]; x=find(x);y=find(y); f[x]=y; } } } if(find(n+1)!=find(n+2)){puts("0");return 0;} addedge(S,getnum(n+1,0),INF); addedge(getnum(n+2,0),T,INF); int DAY;maxf=0; for(DAY=1;maxf<k;DAY++){ addedge(S,getnum(n+1,DAY),INF); addedge(getnum(n+2,DAY),T,INF); for(int i=1;i<=n+2;i++) addedge(getnum(i,DAY-1),getnum(i,DAY),INF); for(int i=1;i<=m;i++){ int x=p[i].s[ (DAY-1) % p[i].r +1 ]; int y=p[i].s[ ( DAY ) % p[i].r +1 ]; addedge(getnum(x,DAY-1),getnum(y,DAY),p[i].p); } dinic(); } printf("%d ",DAY-1); }

    T14 孤岛营救

    分层图最短路
    dis[p,x]记录钥匙获得情况为p,当前到达x号点的最小时间。BFS转移就可以

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 20;
    const int INF = 0x3f3f3f3f;
    int n,m,p,k,s;
    const int mx[]={1,0,-1,0};
    const int my[]={0,1,0,-1};
    int g[255][255];
    vector<int> key[20][20];
    int dis[3200][255];
    typedef pair<int,int>pii;
    queue<pii>q;
    int encode(int x,int y){
        return (x-1)*m+y;
    }
    void decode(int d,int &x,int &y){
        y=d%m;if(y==0)y=m;
        x=(d-y)/m+1;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&p);
        scanf("%d",&k);
        memset(g,0,sizeof(g));
        for(int i=1;i<=k;i++){
            int x1,y1,x2,y2,G;
            scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&G);
            int p=encode(x1,y1),q=encode(x2,y2);
            g[ p ][ q ]=g[ q ][ p ]=G?G:INF;
        }
        scanf("%d",&s);
        memset(key,0,sizeof(key));
        for(int i=1;i<=s;i++){
            int x,y,Q;
            scanf("%d%d%d",&x,&y,&Q);
            key[x][y].push_back(Q);
        }
        memset(dis,-1,sizeof(dis));
    
        for(int i=1;i<=n*m;i++)
        for(int j=1;j<=n*m;j++){
            if(i==j)continue;
            int x1,y1,x2,y2;
            if(g[i][j]==0)continue;
            decode(i,x1,y1);decode(j,x2,y2);
        }
    
        int tmp=1;
        for(int i=0;i<key[1][1].size();i++)tmp|=1<<key[1][1][i];
        dis[ tmp ][ encode(1,1) ]=0;
        q.push(pii(tmp,encode(1,1)));
    
        while(!q.empty()){
            pii u=q.front();q.pop();
            int x=u.second,p=u.first;
            int tx,ty;
            decode(x,tx,ty);
    
            if(tx==n && ty==m){
                cout<<dis[p][x]<<endl;
                return 0;
            }
            for(int i=0;i<4;i++){
                int nx=tx+mx[i];
                int ny=ty+my[i];
                if(nx<1 || nx>n || ny<1 || ny>m)continue;
    
                int y=encode(nx,ny);
    
                if(g[x][y]==INF)continue;
    
                if(g[x][y]==0 || (p & (1<<g[x][y]))){
                    int np=p;
                    for(int j=0;j<key[nx][ny].size();j++)
                        np|=(1<<key[nx][ny][j]);
                    if(dis[np][y]==-1){
                        dis[np][y]=dis[p][x]+1;
                        q.push(pii(np,y));
                    }
                }
            }
        }
        puts("-1");
    }

    T15 汽车加油行驶

    分层图最短路

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 200005;
    const int INF= 0x3f3f3f3f;
    
    int N,K,A,B,C;
    int g[105][105],cnt=0;
    int num(int x,int y,int h){
        return h*N*N + (x-1) * N +y;
    }
    struct edge{
        int x,y,next,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _c):x(_x),y(_y),next(_nt),c(_c){}
    }e[maxn<<2];
    int head[maxn],tot=1,dis[maxn];
    void addedge(int x,int y,int c){
        e[++tot]=edge(x,y,head[x],c);head[x]=tot;
    }
    const int mx[]={1,0,-1,0};
    const int my[]={0,1,0,-1};
    typedef pair<int,int>pii;
    struct heap{
        pii data[maxn<<2];
        int siz;
        public:
            heap(){siz=0;}
            void push(pii x);
            void pop();
            pii top(){return data[1];}
            bool empty(){return siz==0;}
    };
    heap q;
    void Dijkstra(){
        int S=num(1,1,K);
        int T=num(N,N,K)+1;
        for(int i=1;i<=T;i++)dis[i]=i==S?0:INF;
        q.push(pii(dis[S],S));
        while(!q.empty()){
            pii tmp=q.top();q.pop();
            int x=tmp.second;
            if(tmp.first > dis[x])continue;
            for(int y,c,i=head[x];i;i=e[i].next){
                y=e[i].y;c=e[i].c;
                if(dis[y] > dis[x]+c){
                    dis[y]=dis[x]+c;
                    q.push(pii(dis[y],y));
                }
            }
        }
    }
    int main(){
        // freopen("trav.in","r",stdin);
        // freopen("trav2.out","w",stdout);
    
        scanf("%d%d%d%d%d",&N,&K,&A,&B,&C);
        for(int i=1;i<=N;i++)for(int j=1;j<=N;j++){
            scanf("%d",&g[i][j]);
        }
    
        for(int i=1;i<=N;i++)
        for(int j=1;j<=N;j++)
        for(int p=0;p<=K;p++){
            int c=g[i][j]?A:A+C;
            if(p<K)addedge(num(i,j,p),num(i,j,K),c);
            if( (!g[i][j] && p>0) || p==K){
                for(int q=0;q<4;q++){
                    int x=i+mx[q];
                    int y=j+my[q];
                    c=q<2 ?

    0 : B; if(x>=1 && x<=N && y>=1 && y<=N) addedge(num(i,j,p),num(x,y,p-1),c); } } } Dijkstra(); int ans=INF; for(int i=0;i<=K;i++)ans=min(ans,dis[num(N,N,i)]); printf("%d ",ans); } void heap::push(pii x){ data[++siz]=x;int now=siz; while(now>>1){ if(data[now].first<data[now>>1].first){ swap(data[now],data[now>>1]); now>>=1; }else break; } } void heap::pop(){ data[1]=data[siz--];int now=1,next; while(now<<1 < siz){ if(data[now<<1].first<data[now<<1|1].first) next=now<<1;else next=now<<1|1; if(data[now].first>data[next].first){ swap(data[now],data[next]);now=next; }else break; } }

    T16 数字梯形问题

    费用流求不相交路径

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    const int maxn = 50;
    const int INF = 0x3f3f3f3f;
    int n,m,cnt;
    int a[maxn][maxn],num[maxn][maxn];
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c):x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxn<<6];
    int head[maxn*maxn*2],tot,fro[maxn*maxn*2],S,T;
    LL dis[maxn*maxn*2];
    bool inq[maxn*maxn*2];
    queue<int>q;
    inline void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v,c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
        // cout<<tot<<endl;
    }
    bool SPFA(){
        for(int i=S;i<=T;i++)dis[i]=-INF;
        dis[S]=0;
        q.push(S);inq[S]=1;
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int y,v,c,i=head[x];i;i=e[i].next){
                y=e[i].y;v=e[i].v;c=e[i].c;
                if(v && dis[x]+c > dis[y]){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        q.push(y);inq[y]=1;
                    }
                }
            }
        }
        return dis[T]!=-INF;
    }
    LL mcf(){
        LL ret=0;
        while(SPFA()){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&m,&n);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m+i-1;j++)
            scanf("%d",&a[i][j]);
        cnt=0;
        for(int i=1;i<=n;i++)for(int j=1;j<=m+i-1;j++)num[i][j]=++cnt;
        S=0;T=cnt*2+1;
        /*PROBLEM 1*/
        memset(head,0,sizeof(head));tot=1;memset(fro,0,sizeof(fro));
        for(int i=1;i<=m;i++)addedge(S,num[1][i],1,0);
        for(int i=1;i<=m+n-1;i++){addedge(num[n][i]+cnt,T,1,0);addedge(num[n][i],num[n][i]+cnt,1,a[n][i]);}
        for(int i=1;i<n;i++)for(int j=1;j<=m+i-1;j++){
            addedge(num[i][j],num[i][j]+cnt,1,a[i][j]);
            addedge(num[i][j]+cnt,num[i+1][j],1,0);
            addedge(num[i][j]+cnt,num[i+1][j+1],1,0);
        }
        // for(int i=2;i<=tot;i+=2)cout<<e[i].x<<" "<<e[i].y<<" "<<e[i].v<<" "<<e[i].c<<endl;
        printf("%lld
    ",mcf());
    
        /*PROBLEM 2*/
        memset(head,0,sizeof(head));tot=1;memset(fro,0,sizeof(fro));
        for(int i=1;i<=m;i++)addedge(S,num[1][i],1,0);
        for(int i=1;i<=m+n-1;i++){addedge(num[n][i]+cnt,T,INF,0);addedge(num[n][i],num[n][i]+cnt,INF,a[n][i]);}
        for(int i=1;i<n;i++)for(int j=1;j<=m+i-1;j++){
            addedge(num[i][j],num[i][j]+cnt,INF,a[i][j]);
            addedge(num[i][j]+cnt,num[i+1][j],1,0);
            addedge(num[i][j]+cnt,num[i+1][j+1],1,0);
        }
        printf("%lld
    ",mcf());
        /*PROBLEM 3*/
        memset(head,0,sizeof(head));tot=1;memset(fro,0,sizeof(fro));
        for(int i=1;i<=m;i++)addedge(S,num[1][i],1,0);
        for(int i=1;i<=m+n-1;i++){
            addedge(num[n][i]+cnt,T,INF,0);
            addedge(num[n][i],num[n][i]+cnt,INF,a[n][i]);
        }
        for(int i=1;i<n;i++)for(int j=1;j<=m+i-1;j++){
            addedge(num[i][j],num[i][j]+cnt,INF,a[i][j]);
            addedge(num[i][j]+cnt,num[i+1][j],INF,0);
            addedge(num[i][j]+cnt,num[i+1][j+1],INF,0);
        }
        printf("%lld
    ",mcf());
    }
    /*
    2 5
    2 3
    3 4 5
    9 10 9 1
    1 1 10 1 1
    1 1 10 12 1 1
    
    66
    75
    77
    */

    T17 运输问题

    仓库作为二分图X集,零售商店作为Y集。S向Xi连容量ai费用0的边。Yi向T连容量bi费用0的边,Xi向Yi连容量INF费用Cij的边。求最小费用最大流和最大费用最大流就可以。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 205;
    const int maxm = 50005;
    const int INF  = 0x3f3f3f3f;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c)
            :x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxm<<1];
    int head[maxn],tot=1;
    int fro[maxn],dis[maxn];bool inq[maxn];
    void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v, c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    int n,m,S,T;
    int a[maxn],b[maxn],g[105][105];
    bool SPFA(int fg);
    int mcf(int fg);
    void build(){
        tot=1;memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++)addedge(S,i,a[i],0);
        for(int i=1;i<=n;i++)addedge(i+m,T,b[i],0);
        for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)
            addedge(i,j+m,INF,g[i][j]);
    
        // for(int i=2;i<=tot;i+=2)
            // cout<<e[i].x<<" "<<e[i].y<<" "<<e[i].v<<" "<<e[i].c<<endl;
    }
    int main(){ 
        scanf("%d%d",&m,&n);
        S=0;T=n+m+1;
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)scanf("%d",&g[i][j]);
    
        build();
        printf("%d
    ",mcf(1));
        build();
        printf("%d
    ",mcf(-1));
    }
    
    queue<int>q;
    bool SPFA(int fg){
        memset(inq,0,sizeof(inq));
        for(int i=S;i<=T;i++)dis[i]=INF*fg;
        dis[S]=0;q.push(S);inq[S]=1;
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int v,c,y,i=head[x];i;i=e[i].next){
                y=e[i].y;v=e[i].v;c=e[i].c;
                if(v && dis[y]*fg > (dis[x]+c)*fg){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;
                        q.push(y);
                    }
                }
            }
        }
        return dis[T]!=INF*fg;
    }
    int mcf(int fg){
        int ret=0;
        memset(fro,0,sizeof(fro));
        while(SPFA(fg)){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }

    T18 分配问题

    建图方法与T17相似。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 205;
    const int maxm = 50005;
    const int INF  = 0x3f3f3f3f;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c)
            :x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxm];
    int tot,head[maxn],S,T,n,fro[maxn],dis[maxn];
    int g[105][105];
    bool inq[maxn];
    inline void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v, c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    bool SPFA(int fg);
    int mcf(int fg);
    void build(){
        tot=1;memset(head,0,sizeof(head));
        S=0;T=n*2+1;
        for(int i=1;i<=n;i++){
            addedge(S,i,1,0);
            addedge(i+n,T,1,0);
        }
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
            addedge(i,j+n,INF,g[i][j]);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&g[i][j]);
    
        build();
        printf("%d
    ",mcf(1));
        build();
        printf("%d
    ",mcf(-1));
    }
    queue<int>q;
    bool SPFA(int fg){
        for(int i=S;i<=T;i++)dis[i]=INF*fg;
        dis[S]=0;inq[S]=1;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int y,c,v,i=head[x];i;i=e[i].next){
                y=e[i].y;v=e[i].v;c=e[i].c;
                if(v && dis[y]*fg > (dis[x]+c)*fg ){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;q.push(y);
                    }
                }
            }
        }
        return dis[T]!=INF*fg;
    }
    int mcf(int fg){
        int ret=0;
        memset(fro,0,sizeof(fro));
        while(SPFA(fg)){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }

    T19 负载平衡问题

    供求平衡问题,费用流解决

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 500;
    const int INF  = 0x3f3f3f3f;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c):x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[ 2400 ];
    int head[maxn],tot=1;
    int dis[maxn],fro[maxn],a[maxn];
    bool inq[maxn];
    queue<int>q;
    int S,T,n;
    inline void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v,c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    bool SPFA(){
        for(int i=S;i<=T;i++)dis[i]=INF,inq[i]=0;
        q.push(S);inq[S]=1;
        dis[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            inq[x]=0;
            for(int y,v,c,i=head[x];i;i=e[i].next){
                y=e[i].y;v=e[i].v;c=e[i].c;
                if(v && dis[x]+c<dis[y]){
                    dis[y]=dis[x]+c;fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;q.push(y);
                    }
                }
            }
        }
        return dis[T]!=INF;
    }
    int mcf(){
        int ret=0;
        while(SPFA()){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }
    
    int main(){
        scanf("%d",&n);
        int sum=0;
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);sum+=a[i];}
        sum/=n;
        for(int i=1;i<=n;i++)a[i]=a[i]-sum;
        S=0;T=n*2+1;
        for(int i=1;i<=n;i++){
            if(a[i] > 0)
                addedge(S,i,a[i],0);
            else
                addedge(i+n,T,-a[i],0);
            int t;
            t=i>1?i-1:n;
            addedge(i,t,INF,1);addedge(i,n+t,INF,1);
            t=i<n?i+1:1;
            addedge(i,t,INF,1);addedge(i,n+t,INF,1);
        }
        cout<<mcf()<<endl;
    }

    T20 深海机器人问题

    网格上的边连两条,一条容量1费用为其价值。还有一条容量INF费用为0,求最大费用最大流。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 500;
    const int maxm = 50005;
    const int INF  = 0x3f3f3f3f;
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c)
            :x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxm];
    int  tot=1,head[maxn],fro[maxn],dis[maxn],S,T,a,b,P,Q;
    int num[25][25];
    bool inq[maxn];
    void addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v,c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    queue<int>q;
    bool SPFA(){
        for(int i=S;i<=T;i++)dis[i]=-INF;
        q.push(S);dis[S]=0;inq[S]=1;
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int y,c,v,i=head[x];i;i=e[i].next){
                y=e[i].y,v=e[i].v,c=e[i].c;
                if(v && dis[y] < dis[x]+c){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;q.push(y);
                    }
                }
            }
        }
        return dis[T]!=-INF;
    }
    int mcf(){
        int ret=0;
        while(SPFA()){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=dis[T]*tmp;
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&a,&b);
        scanf("%d%d",&P,&Q);P++;Q++;
        T=0;
        for(int i=1;i<=P;i++)
        for(int j=1;j<=Q;j++)
            num[i][j]=++T;
        S=0;T++;
    
        for(int i=1;i<=P;i++)
        for(int j=1;j<=Q-1;j++){
            int c;
            scanf("%d",&c);
            int x=num[i][j],y=num[i][j+1];
            addedge(x,y,1,c);
            addedge(x,y,INF,0);
        }
        for(int i=1;i<=Q;i++)
        for(int j=1;j<=P-1;j++){
            int c;
            scanf("%d",&c);
            int x=num[j][i],y=num[j+1][i];
            addedge(x,y,1,c);
            addedge(x,y,INF,0);
        }
        for(int i=1;i<=a;i++){
            int k,x,y;
            scanf("%d%d%d",&k,&x,&y);x++;y++;
            addedge(S,num[x][y],k,0);
        }
        for(int i=1;i<=b;i++){
            int k,x,y;
            scanf("%d%d%d",&k,&x,&y);x++;y++;
            addedge(num[x][y],T,k,0);
        }
        printf("%d
    ",mcf());
    }

    T21 最长K可重区间集问题

    将全部出现过的坐标离散化,保存每一个区间的长度。从S到最左边点连容量为k费用为0的边,最左边的点到T连容量为K费用为0的边,全部i到i+1连容量为1费用为0的边,每一个区间的左右端点所相应的点之间连容量为1费用为区间长度的边,求最大费用最大流。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1005;
    const int maxm = 100005;
    const int INF  = 0x3f3f3f3f;
    #define MADOKA main
    struct edge{
        int x,y,next,v,c;
        edge(){}
        edge(int _x,int _y,int _nt,int _v,int _c)
        :x(_x),y(_y),next(_nt),v(_v),c(_c){}
    }e[maxm];
    int tot=1,head[maxn],fro[maxn],dis[maxn],n,k,S,T=0;
    bool inq[maxn];
    struct node{
        int k,p;
    }a[maxn];
    int b[maxn<<1],L[maxn];
    bool cmp(node x,node y){return x.k<y.k;}
    inline int addedge(int x,int y,int v,int c){
        e[++tot]=edge(x,y,head[x],v, c);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0,-c);head[y]=tot;
    }
    queue<int>q;
    bool SPFA(){
        for(int i=S;i<=T;i++)dis[i]=-INF;
        dis[S]=0;inq[S]=1;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();inq[x]=0;
            for(int y,v,c,i=head[x];i;i=e[i].next){
                y=e[i].y;v=e[i].v;c=e[i].c;
                if( v && dis[y] < dis[x]+c){
                    dis[y]=dis[x]+c;
                    fro[y]=i;
                    if(!inq[y]){
                        inq[y]=1;q.push(y);
                    }
                }
            }
        }
        return dis[T]!=-INF;
    }
    int mcf(){
        int ret=0;
        while(SPFA()){
            int tmp=INF;
            for(int i=fro[T];i;i=fro[e[i].x])tmp=min(tmp,e[i].v);
            ret+=tmp*dis[T];
            for(int i=fro[T];i;i=fro[e[i].x])e[i].v-=tmp,e[i^1].v+=tmp;
        }
        return ret;
    }
    int MADOKA(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&b[i],&b[i+n]);L[i]=b[i+n]-b[i];
            a[i].k=b[i];
            a[i+n].k=b[i+n];
            a[i].p=i; 
            a[i+n].p=i+n;
        }
        sort(a+1,a+1+n+n,cmp);
        int cnt=0;
        b[a[1].p]=++T;
        for(int i=2;i<=n<<1;i++)
            b[a[i].p]=a[i].k==a[i-1].k?T:++T;
        T++;
        S=0;
        addedge(S,1,k,0);addedge(T-1,T,k,0);
        for(int i=1;i<=T-2;i++)addedge(i,i+1,INF,0);
        for(int i=1;i<=n;i++)addedge(b[i],b[i+n],1,L[i]);
        printf("%d
    ",mcf());
    }

    T24 骑士共存问题

    骑士仅仅能从白格跳到黑格,再从黑格跳到白格。所以就是求二分图最大点独立集。

    二分图最大点独立集等于总点数-匹配数
    我的网络流跑太慢了!!。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    using namespace std;
    const int maxn = 205;
    const int INF  = 0x3f3f3f3f;
    int g[maxn][maxn];
    int n,m,S=0,T=0;
    const int mx[]={1,2,2,1,-1,-2,-2,-1};
    const int my[]={-2,-1,1,2,2,1,-1,-2};
    struct edge{
        int x,y,next,v;
        edge(){}
        edge(int _x,int _y,int _nt,int _v)
        :x(_x),y(_y),next(_nt),v(_v){}
    }e[maxn*maxn*16];
    int head[maxn*maxn],cur[maxn*maxn],tot=1,h[maxn*maxn];
    inline void addedge(int x,int y,int v){
        e[++tot]=edge(x,y,head[x],v);head[x]=tot;
        e[++tot]=edge(y,x,head[y],0);head[y]=tot;
    }
    int q[maxn*maxn],l,r;
    bool BFS(){
        memset(h,-1,sizeof(h));
        h[S]=0;
        q[l=r=0]=S;
        while(l<=r){
            int x=q[l++];
            if(x==T)return 1;
            for(int v,y,i=head[x];i;i=e[i].next){
                y=e[i].y,v=e[i].v;
                if(v && h[y]==-1){
                    h[y]=h[x]+1;
                    if(y==T)return 1;
                    q[++r]=y;
                }
            }
        }
        return 0;
    }
    int DFS(int x,int f){
        if(x==T)return f;
        int used=0,tmp;
        for(int v,y,i=cur[x];i;i=e[i].next){
            y=e[i].y;v=e[i].v;
            if(v && h[y]==h[x]+1){
                tmp=DFS(y,min(v,f-used));
                e[i].v-=tmp;e[i^1].v+=tmp;
                used+=tmp;
                if(e[i].v)cur[x]=i;
                if(f==used)return f;
            }
        }
        if(!used)h[x]=-1;
        return used;
    }
    int maxf(){
        int ret=0;
        while(BFS()){
            for(int i=S;i<=T;i++)cur[i]=head[i];
            ret+=DFS(S,INF);        
        }
        return ret;
    }
    int main(){
        scanf("%d%d",&n,&m);
        memset(g,0,sizeof(g));
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            g[x][y]=-1;
        }
    
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
            if(g[i][j] == 0)g[i][j]=++T;
        S=0;T=n*n+1;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(g[i][j]==-1)continue;
            if((i+j) % 2 == 0){
                addedge(S,g[i][j],1);
                for(int k=0;k<8;k++){
                    int x=i+mx[k],y=j+my[k];
                    if(x<1 || x>n || y<1 || y>n)continue;
                    if(g[x][y]==-1)continue;
                    addedge(g[i][j],g[x][y],INF);
                }
            }else{
                addedge(g[i][j],T,1);
            }
        }
        printf("%d
    ",n*n-m-maxf());
    }
  • 相关阅读:
    C语言基础
    R安装包
    随笔
    计算机组成原理(三)--存储器的层次结构
    计算机组成原理(一)
    查找
    二叉树
    Mesos
    第三章 线性表
    第四章 栈与队列
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7201316.html
Copyright © 2020-2023  润新知