• 网络流汇总....


    1 Poj 1149(最大流建图

    题目:有m个猪圈,n个顾客,n个顾客依次到达,每个顾客可以打开若干个猪圈,可以选择给当前顾客卖不超过b头猪,并且当前打开的猪圈中的猪可以任意调整。问最多能卖多少猪。

    思路:首先是直观的建图,由于有顺序关系,所以考虑给每个顾客建一层图,那么节点数就是n×m,这个数目太大。可以注意到原图中有很多OO权的边,比如可以相互转移的猪圈之间的边。这些边是可以化简的。具体化简思路见http://ycool.com/post/zhhrrm6#pic1

    化简之后的图即为:原点向每个猪圈的第一个顾客连边,流量为猪圈里猪的数目。每个顾客向下一个到达这个猪圈的顾客连无穷的边。顾客向汇点连边。

    理解:首先这么建图体现了顺序性,每个顾客的可选的猪的数目与前一个到猪圈的顾客选了多少有关。分配方面,每个顾客都和所有的来源连边了,并且流过来的流量是前面决策之后的。

    化简的重点是来源,去向。后到的顾客可选的是前面的顾客选剩下的。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxv=100000;
    struct EDGE{
        int to,cap,rev;
        EDGE(int t,int c,int r):to(t),cap(c),rev(r){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap){///加边
        G[from].pb(EDGE(to,cap,G[to].size()));
        G[to].pb(EDGE(from,0,G[from].size()-1));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    const int maxn=2000;
    vector<int> cus[maxn];
    int pig[maxn];
    int need[maxn];
    int n,m;
    void build(){
        for(int i=1;i<=m;i++){
            if(cus[i].size()){
                addedge(s,cus[i][0],pig[i]);
            }
            for(int j=1;j<cus[i].size();j++){
                addedge(cus[i][j-1],cus[i][j],INF);
            }
        }
        for(int i=1;i<=n;i++){
            addedge(i,t,need[i]);
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>m>>n;
        for(int i=1;i<=m;i++){
            scanf("%d",&pig[i]);
        }
        for(int i=1;i<=n;i++){
            int a;
            scanf("%d",&a);
            for(int j=0;j<a;j++){
                int k;
                scanf("%d",&k);
                cus[k].pb(i);
            }
            scanf("%d",&need[i]);
        }
        build();
        printf("%d",dinic(s,t));
        return 0;
    }
    View Code

     2 POJ 1637(混合图欧拉回路判定

    题目:给出若干有向或无向边,问是否有欧拉回路。

    思路:见http://www.cnblogs.com/kuangbin/p/3537525.html

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxv=100000;
    struct EDGE{
        int to,cap,rev;
        EDGE(int t,int c,int r):to(t),cap(c),rev(r){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap){///加边
        G[from].pb(EDGE(to,cap,G[to].size()));
        G[to].pb(EDGE(from,0,G[from].size()-1));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    const int maxn=1200;
    int T;
    int m,S;
    int es[maxn][3];
    int d[maxn];
    vector<int> nG[maxn];
    bool vis[maxn];
    void init(){
        memset(d,0,sizeof d);
        memset(vis,0,sizeof vis);
        G[s].clear();G[t].clear();
        for(int i=1;i<=m;i++){
            G[i].clear();nG[i].clear();
        }
    }
    void dfs(int v){
        vis[v]=1;
        for(int i=0;i<nG[v].size();i++){
            int u=nG[v][i];
            if(vis[u]) continue;
            dfs(u);
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>T;
        while(T--){
            cin>>m>>S;
            init();
            for(int i=0;i<S;i++){
                scanf("%d%d%d",&es[i][0],&es[i][1],&es[i][2]);
                es[i][2]^=1;
                nG[es[i][0]].pb(es[i][1]);
                nG[es[i][1]].pb(es[i][0]);
                d[es[i][1]]++,d[es[i][0]]--;
            }
            dfs(1);
            bool f=1;
            for(int i=1;i<=m;i++)
                if(!vis[i]){
                    f=0;
                    break;
                }
            for(int i=1;i<=m;i++){
                if(d[i]%2!=0){
                    f=0;break;
                }
            }
            if(!f){
                puts("impossible");
                continue;
            }
            for(int i=0;i<S;i++){
                int x=es[i][0],y=es[i][1],z=es[i][2];
                if(z){
                    addedge(y,x,1);
                }
            }
            int sum=0;
            for(int i=1;i<=m;i++){
                if(d[i]>0){
                    sum+=d[i]/2;
                    addedge(s,i,d[i]/2);
                }else{
                    addedge(i,t,-(d[i]/2));
                }
            }
            int res=dinic(s,t);
            if(res==sum){
                puts("possible");
            }else{
                puts("impossible");
            }
        }
        return 0;
    }
    View Code

     3 sgu194 Reactor Cooling(无源汇有上下界的网络流

    思路见:http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html

    把有下界限制的边减去下界,然后增加超级源点汇点处理下界流量,如果下界流量满流则有解,否则无解。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxv=100000;
    struct EDGE{
        int to,cap,rev;
        int id;
        EDGE(int t,int c,int r,int id):to(t),cap(c),rev(r),id(id){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap,int id){///加边
        G[from].pb(EDGE(to,cap,G[to].size(),id));
        G[to].pb(EDGE(from,0,G[from].size()-1,-id));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    const int maxm=50000;
    int n,m;
    int es[maxm][4];
    int a[4];
    int d[maxm];
    int ans[maxm];
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            for(int j=0;j<4;j++){scanf("%d",&a[j]);}
            for(int j=0;j<4;j++){es[i][j]=a[j];}
            addedge(a[0],a[1],a[3]-a[2],i);
            d[a[0]]-=a[2];
            d[a[1]]+=a[2];
        }
        int sum=0,sumn=0;
        for(int i=1;i<=n;i++){
            if(d[i]>0){
                sum+=d[i];
                addedge(s,i,d[i],m+1);
            }else{
                sumn+=-d[i];
                addedge(i,t,-d[i],m+1);
            }
        }
        if(sum!=sumn){
            puts("NO");
            return 0;
        }
        int res=dinic(s,t);
        if(res==sum){
            puts("YES");
            for(int v=1;v<=n;v++){
                for(int j=0;j<G[v].size();j++){
                    EDGE &e=G[v][j];
                    if(e.id<0){
                        ans[-e.id]=e.cap+es[-e.id][2];
                    }
                }
            }
            for(int i=1;i<=m;i++){
                printf("%d
    ",ans[i]);
            }
        }else{
            puts("NO");
        }
        return 0;
    }
    View Code

     4 zoj3229 Shoot the Bullet(有源汇有上下界的最大流

    思路:在汇点到源点加一条容量无穷的边,然后方法同无源汇的情况。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxv=100000;
    struct EDGE{
        int to,cap,rev;
        EDGE(int t,int c,int r):to(t),cap(c),rev(r){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap){///加边
        G[from].pb(EDGE(to,cap,G[to].size()));
        G[to].pb(EDGE(from,0,G[from].size()-1));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    int ss=s-3,tt=ss-1;
    const int maxm=1400;
    int n,m;
    int g[maxv];
    int R[366][1005];
    int d[maxv];
    void init(){
        for(int i=0;i<n+m+1;i++){
            G[i].clear();
        }
        G[s].clear();G[t].clear();
        G[ss].clear();G[tt].clear();
        clr(d);clr(R);
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(cin>>n>>m){
            init();
            for(int i=1;i<=m;i++){
                scanf("%d",&g[i]);
                addedge(i,t,INF);
                d[i]-=g[i],d[t]+=g[i];
            }
            for(int i=1;i<=n;i++){
                int C,D;
                scanf("%d%d",&C,&D);
                addedge(s,i+m,D);
                for(int j=1;j<=C;j++){
                    int tar,l,r;
                    scanf("%d%d%d",&tar,&l,&r);
                    tar++;
                    addedge(i+m,tar,r-l);
                    d[i+m]-=l,d[tar]+=l;
                    R[i][tar]=r;
                }
            }
            int sum=0;
            addedge(ss,t,d[t]);
            sum+=d[t];
            for(int i=1;i<=m+n;i++){
                if(d[i]>0){
                    sum+=d[i];
                    addedge(ss,i,d[i]);
                }else{
                    addedge(i,tt,-d[i]);
                }
            }
            addedge(t,s,INF);
            int res=dinic(ss,tt);
            if(res!=sum){
                puts("-1
    ");
                continue;
            }
            G[ss].clear();G[tt].clear();
            int res2=dinic(s,t);
            printf("%d
    ",res2);
            for(int i=1;i<=n;i++){
                int v=i+m;
                for(int j=0;j<G[v].size();j++){
                    EDGE &e=G[v][j];
                    if(e.to<=m&&e.to>=1){
                        printf("%d
    ",R[i][e.to]-e.cap);
                    }
                }
            }
            puts("");
        }
        return 0;
    }
    View Code

     5 sgu176(有上下界的最小流

    思路:限制边流量建图,先跑ss到tt的最大流,加t到s的边,再跑一次ss到tt的最大流,注意加边必须跑一次再加。。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxv=100000;
    struct EDGE{
        int to,cap,rev;
        int id;
        EDGE(int t,int c,int r,int id):to(t),cap(c),rev(r),id(id){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap,int id){///加边
        G[from].pb(EDGE(to,cap,G[to].size(),id));
        G[to].pb(EDGE(from,0,G[from].size()-1,-id));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    const int maxm=10000;
    int ss=s-3,tt=ss-1;
    int n,m;
    int full[maxm];
    int flow[maxm];
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n>>m;
        s=1,t=n;
        int sum=0;
        for(int i=1;i<=m;i++){
            int a,b,c,d;
            scanf("%d%d%d%d",&a,&b,&c,&d);
            if(d){
                full[i]=c;
                addedge(a,tt,c,i);
                addedge(ss,b,c,i);
                sum+=c;
            }else{
                addedge(a,b,c,i);
            }
        }
        int res=dinic(ss,tt);
        addedge(t,s,INF,INF);
        int res2=dinic(ss,tt);
        if(res+res2!=sum){
            puts("Impossible");
        }else{
            int ans=G[s].bk.cap;
            cout<<ans<<endl;
            for(int i=1;i<=n;i++){
                for(int j=0;j<G[i].size();j++){
                    EDGE &e=G[i][j];
                    if(e.id<0&&-e.id<=m){
                        flow[-e.id]=e.cap;
                    }
                }
            }
            for(int i=1;i<=m;i++){
                printf("%d ",flow[i]);
            }
        }
        return 0;
    }
    View Code

     6 poj2699

    题目:小于10个人进行锦标赛,共n*(n-1)/2场,如果某个人赢了所有胜场比他多的人,那么他非常叼,现在要求最多有多少人很叼。

    思路:如果人数为k,那么必然可以构造出分数最大的人是叼人的分配方式,所以枚举人数即可。建图,对于必须要赢的场,胜者建边,其他场建两条边。源点向每个人建胜场条边。

    然后跑最大流,同时可以得到分配方式。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-7)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (a))
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<int,int> P;
    
    
    const int maxv=1000;
    struct EDGE{
        int to,cap,rev;
        EDGE(int t,int c,int r):to(t),cap(c),rev(r){}
    };
    vector<EDGE> G[maxv];
    void addedge(int from,int to,int cap){///加边
        G[from].pb(EDGE(to,cap,G[to].size()));
        G[to].pb(EDGE(from,0,G[from].size()-1));
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=0;i<G[v].size();i++){
                EDGE &e=G[v][i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i<G[v].size();i++){
            EDGE &e=G[v][i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    G[e.to][e.rev].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            memset(iter,0,sizeof iter);
            int f;
            while((f=dfs(s,t,IINF))>0) flow+=f;
        }
        return 0;
    }
    
    int T;
    char r[1000];
    vector<int> a;
    int n;
    void get(){
        a.clear();
        int len=strlen(r);
        for(int i=0;i<len;i+=2){
            a.pb(r[i]-'0');
        }
        sort(a.begin(),a.end());
        n=a.size();
    }
    int ans;
    void build(int k){
        for(int i=0;i<maxv;i++) G[i].clear();
        for(int i=n-k;i<n;i++){
            for(int j=i+1;j<n;j++){
                addedge(i,(i+1)*n+j,1);
                if(a[i]==a[j]) addedge(j,(i+1)*n+j,1); 
            }
        }
        for(int i=n;i<n*(n+2);i++){
            addedge(i,t,1);
        }
        for(int i=0;i<n-k;i++){
            for(int j=i+1;j<n;j++){
                addedge(i,(i+1)*n+j,1);
                addedge(j,(i+1)*n+j,1);
            }
        }
        for(int i=0;i<n;i++){
            addedge(s,i,a[i]);
        }
    }
    void solve(){
        int tar=n*(n-1)/2;
        for(int i=1;i<=n;i++){
            build(i);
            int d=dinic(s,t);
            if(d==tar) ans=i;
            else break;
        }
        printf("%d
    ",ans);
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>T;
        gets(r);
        while(T--){
            gets(r);
            get();
            solve();
        }
        return 0;
    
    }
    View Code

     7 poj3084(最小割

    题目:若干个房间,有些房间有入侵者,有些房间是要保护的,还有些只有一面能打开的锁,问最小关几道门保护所有需要保护的房间。

    思路:最小割,不过对于关不住的点我是打算暴力dfs的,看到题解直接连一条INF的边,确实简洁高效。(代码暂时没有。。

    8 PKU 3308(最小割

    题目:要攻击l个格子,攻击每行或每列有个花费,求攻击到所有格子的最小花费。

    思路:首先行列分开建图是常见方法,然后这个是求最小花费,考虑最小割求解。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000300)
    #define FINF (1e9)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    #define mset(x,v) memset((x),(v),sizeof (x))
    
    template <class T>
    inline bool scan_d(T &ret) {
        char c;
        int sgn;
        if(c=getchar(),c==EOF) return 0; //EOF
        while(c!='-'&&(c<'0'||c>'9')) c=getchar();
        sgn=(c=='-')?-1:1;
        ret=(c=='-')?0:(c-'0');
        while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
        ret*=sgn;
        return 1;
    }
    inline void out(long long x) {
        if(x>9) out(x/10);
        putchar(x%10+'0');
    }
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    
    const int maxv=2000;
    struct EDGE{
        int to,next;
        double cap;
    }ES[maxv*2];
    int head[maxv];
    int eh;
    void addedge(int from,int to,double cap){///加边
        ES[eh].to=to,ES[eh].cap=cap,ES[eh].next=head[from];
        head[from]=eh++;
        ES[eh].to=from,ES[eh].cap=0,ES[eh].next=head[to];
        head[to]=eh++;
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    double dfs(int v,int t,double f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(e.cap>0&&level[e.to]>level[v]){
                double d=dfs(e.to,t,fmin(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    ES[i^1].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    double dinic(int s,int t){///dinic算法求解最大流
        double flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            for(int i=0;i<maxv;i++) iter[i]=head[i];
            double f;
            while((f=dfs(s,t,FINF))>0) flow+=f;
        }
        return 0;
    }
    void clear(){
        memset(head,-1,sizeof head);
        eh=0;
    }
    
    const int maxn=1e5;
    int T;
    int n,m,l;
    double cm[maxn],cn[maxn];
    int main(){
        //freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>T;
        while(T--){
            clear();
            scan_d(m);scan_d(n);scan_d(l);
            for(int i=0;i<m;i++){
                scanf("%lf",&cm[i]);
                cm[i]=log(cm[i]);
                addedge(s,i,cm[i]);
            }
            for(int i=0;i<n;i++){
                scanf("%lf",&cn[i]);
                cn[i]=log(cn[i]);
                addedge(i+m,t,cn[i]);
            }
            for(int i=0;i<l;i++){
                int r,c;
                scan_d(r);scan_d(c);
                addedge(r-1,c-1+m,FINF);
            }
            double ans=dinic(s,t);
            printf("%.4f
    ",exp(ans));
        }
        return 0;
    }
    View Code

     9 poj 2125(二分图最小点权覆盖

    题目:一个有向图,对于每个点,可以选择删除这个点所有的出边,或所有的出边。求删除图上所有边的最小花费。

    思路:明显是一个二分图,一条边要么在入点删除,要么在出点删除,二者必有至少一个。建图之后转化为最小点权覆盖。对于每个网络上的路径,必有s,u,v,t的路径,由于u,v的边不可能在最小割上,那么割中必然有s,u,或v,t中的一条边。那么求得最小割后,从s不可达的点必然在割中,而从s可达的点,其割必然在v到t的边中,所以从s可达的vt边必然是割边(满流)否则有s到t的通路,注意满流的vt边不一定是割边。

    /*
    * @author:  Cwind
    */
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000300)
    #define FINF (1e9)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    #define mset(x,v) memset((x),(v),sizeof (x))
    
    template <class T>
    inline bool scan_d(T &ret) {
        char c;
        int sgn;
        if(c=getchar(),c==EOF) return 0; //EOF
        while(c!='-'&&(c<'0'||c>'9')) c=getchar();
        sgn=(c=='-')?-1:1;
        ret=(c=='-')?0:(c-'0');
        while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
        ret*=sgn;
        return 1;
    }
    inline void out(long long x) {
        if(x>9) out(x/10);
        putchar(x%10+'0');
    }
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<int,int> P;
    
    const int maxv=1000;
    struct EDGE{
        int to,cap,next;
    }ES[maxv*15];
    int head[maxv];
    int eh;
    void addedge(int from,int to,int cap){///加边
        ES[eh].to=to,ES[eh].cap=cap,ES[eh].next=head[from];
        head[from]=eh++;
        ES[eh].to=from,ES[eh].cap=0,ES[eh].next=head[to];
        head[to]=eh++;
    }
    int s=maxv-1;
    int t=maxv-2;
    int level[maxv];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[maxv];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    ES[i^1].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            for(int i=0;i<maxv;i++) iter[i]=head[i];
                int f;
            while((f=dfs(s,t,IINF))>0){
                flow+=f;;
            }
        }
        return 0;
    }
    void dinic_init(){
        memset(head,-1,sizeof head);
        eh=0;
    }
    const int maxn=1000;
    int n,m;
    int w1[maxn],w2[maxn];
    vector<P> oo;
    bool vis[maxv];
    void getans(int v){
        vis[v]=1;
        for(int i=head[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(e.cap>0&&!vis[e.to]) getans(e.to);
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(cin>>n>>m){
            dinic_init();
            for(int i=1;i<=n;i++){
                scan_d(w1[i]);
                addedge(s,i,w1[i]);
            }
            for(int i=1;i<=n;i++){
                scan_d(w2[i]);
                addedge(i+n,t,w2[i]);
            }
            for(int i=0;i<m;i++){
                int x,y;
                scan_d(x);scan_d(y);
                addedge(y,x+n,INF);
            }
            int ans=dinic(s,t);
            out(ans);
            puts("");
            getans(s);
            for(int i=1;i<=n;i++) if(!vis[i]) oo.pb(P(i,1));
            for(int i=n+1;i<=n+n;i++) if(vis[i]) oo.pb(P(i-n,0));
            out(oo.size());
            puts("");
            for(int i=0;i<oo.size();i++) printf("%d %c
    ",oo[i].fs,oo[i].se==0?'-':'+');
        }
        return 0;
    }
    View Code

     10 POJ 1486(二分匹配必须边

    题目:有若干矩形和若干标号,只要是在矩形内的就有可能是该矩形的标号,问有多少矩形的标号是确定的。

    思路:先跑匈牙利做一次二分匹配,然后枚举每个匹配中的边,删除该边,如果匹配数目不变则不是必须边,否则为必须边。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000300)
    #define FINF (1e9)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    #define mset(x,v) memset((x),(v),sizeof (x))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<int,int> P;
    
    const int maxn=60;
    int n;
    struct juxing{
        int x[2],y[2];
    }A[maxn];
    P B[maxn];
    bool ison(P a,juxing x){
        return (a.fs<x.x[1]&&a.fs>x.x[0])&&(a.se<x.y[1]&&a.se>x.y[0]); 
    }
    bool mat[maxn*2][maxn*2];
    bool vis[maxn];
    int match[maxn];
    int V;
    bool dfs(int v){
        vis[v]=1;
        for(int i=1;i<=V;i++){
            int w=match[i];
            if(!mat[v][i]) continue;
            if(w==-1||!vis[w]&&dfs(w)){
                match[v]=i;
                match[i]=v;
                return 1;
            }
        }
        return 0;
    }
    void bi_match(){
        memset(match,-1,sizeof match);
        for(int i=1;i<=V;i++){
            if(match[i]==-1){
                memset(vis,0,sizeof vis);
                dfs(i);
            }
        }
    }
    void init(){
        memset(mat,0,sizeof mat);
    }
    vector<P> ans;
    void solve(){
        ans.clear();
        for(int i=1;i<=n;i++){
            if(match[i]!=-1){
                int w=match[i];
                match[i]=match[w]=-1;
                mat[i][w]=mat[w][i]=0;
                memset(vis,0,sizeof vis);
                if(!dfs(i)){
                    ans.pb(P(w-n,i));
                    match[i]=w;
                    match[w]=i;
                }
                mat[w][i]=mat[i][w]=1;
            }
        }
    }
    int cas;
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(scanf("%d",&n),n!=0){
            V=n*2;
            init();
            for(int i=1;i<=n;i++){
                scanf("%d%d%d%d",&A[i].x[0],&A[i].x[1],&A[i].y[0],&A[i].y[1]);
            }
            for(int i=1;i<=n;i++){
                scanf("%d%d",&B[i].fs,&B[i].se);
            }
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if(ison(B[i],A[j])){
                        mat[i][j+n]=mat[j+n][i]=1;
                    }
                }
            }
            printf("Heap %d
    ",++cas);
            bi_match();
            solve();
            if(!ans.size()){
                puts("none");
            }else{
                sort(ans.begin(),ans.end());
                for(int i=0;i<ans.size();i++){
                    printf("(%c,%d) ",(char)(ans[i].fs+'A'-1),ans[i].se);
                }
                puts("");
            }
            puts("");
        }
        return 0;
    }
    View Code

     11 poj 3692(两个完全图组成的二分图的最大完全匹配

    题目:每个女孩都互相认识,每个男孩也互相认识,还有若干对男女认识。然后求最大的一组人,组内都互相认识。

    思路:这个图的补是个二分图,然后求这个二分图的最大独立集即可(此时独立集是互相没有边的最大组,也就是互相都认识!)。思路挺巧妙的。。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000300)
    #define FINF (1e9)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    #define mset(x,v) memset((x),(v),sizeof (x))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<int,int> P;
    
    const int maxn=600;
    int match[maxn];
    bool used[maxn];
    bool mat[maxn][maxn];
    int g,b,m;
    int V;
    bool dfs(int v){
        used[v]=1;
        for(int i=1;i<=V;i++){
            int u=i;
            if(mat[v][u]||(i<=g&&v<=g||i>g&&v>g)) continue;
            int w=match[u];
            if(w==-1||!used[w]&&dfs(w)){
                match[v]=u;
                match[u]=v;
                return 1;
            }
        }
        return 0;
    }
    int bi_match(){
        memset(match,-1,sizeof match);
        int cnt=0;
        for(int i=1;i<=V;i++){
            if(match[i]==-1){
                memset(used,0,sizeof used);
                if(dfs(i)) cnt++;
            }
        }
        return cnt;
    }
    void init(){    
        memset(mat,0,sizeof mat);
    }
    int cas;
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(scanf("%d%d%d",&g,&b,&m)&&!(!g&&!b&&!m)){
            init();
            V=g+b;
            for(int i=0;i<m;i++){
                int x,y;
                scanf("%d%d",&x,&y);
                mat[x][y+g]=mat[y+g][x]=1;
            }
            printf("Case %d: %d
    ",++cas,g+b-bi_match());
        }    
        return 0;
    }
    View Code

     12 poj 2226(二分匹配,最小点覆盖

    题目:在一个r×c的网格上有若干个点需要覆盖,每次可以覆盖连续的多个在一条直线上的点,可以重复覆盖。问最小需要覆盖多少次。

    思路:每个点只有两种可能的覆盖方式,横着或者竖着,我们把两种覆盖方式建成点,如果两块板子可以覆盖同一个点,就在这两个板子之间连一条边,那么就是二分图的最小点覆盖问题,等于二分图的最大匹配。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    const int maxn=6000;
    int match[maxn];
    bool used[maxn];
    vector<int> G[maxn];
    bool dfs(int v){
        used[v]=1;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            int w=match[u];
            if(w==-1||!used[w]&&dfs(w)){
                match[v]=u;
                match[u]=v;
                return 1;
            }
        }
        return 0;
    }
    int cas;
    char B[100][100];
    char r[100];
    int R,C;
    int sz;
    int id[maxn];
    int max_match(){
        memset(match,-1,sizeof match);
        int cnt=0;
        for(int i=R*C;i<=sz;i++){
            if(match[i]==-1){
                memset(used,0,sizeof used);
                if(dfs(i)) cnt++;
            }
        }
        return cnt;
    }
    void build(){
        for(int i=0;i<R;i++){
            for(int j=0;j<C;j++){
                if(B[i][j]=='*'){
                    sz++;
                    while(B[i][j]=='*'){
                        id[i*C+j]=sz;
                        j++;
                    }
                }
            }
        }
        for(int j=0;j<C;j++){
            for(int i=0;i<R;i++){
                if(B[i][j]=='*'){
                    sz++;
                    while(B[i][j]=='*'){
                        int xx=i*C+j;
                        G[sz].pb(id[xx]);
                        G[id[xx]].pb(sz);
                        i++;
                    }
                }
            }
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(scanf("%d%d",&R,&C)!=EOF){
            sz=R*C-1;
            for(int i=0;i<R;i++){
                scanf("%s",r);
                for(int j=0;j<C;j++){
                    B[i][j]=r[j];
                }
            }
            build();
            int ma=max_match();
            printf("%d
    ",ma);
        }    
        return 0;
    }
    View Code

     13 poj 2195(二分图最大匹配

    题目:有n个人和n个房子,每个人分配一个房子,要求使得总移动距离之和最小的分配。

    思路:二分图最小权匹配,模板题。也可以用费用流做。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    
    
    const int N = 310;
    int nx,ny;//两边的点数
    int g[N][N];//二分图描述
    int linker[N],lx[N],ly[N];//y中各点匹配状态,x,y中的点标号
    int slack[N];
    bool visx[N],visy[N];
    bool DFS(int x){
        visx[x] = true;
        for(int y = 0; y < ny; y++){
            if(visy[y])continue;
            int tmp = lx[x] + ly[y] - g[x][y];
            if(tmp == 0){
                visy[y] = true;
                if(linker[y] == -1 || DFS(linker[y])){
                    linker[y] = x;
                    return true;
                }
            }
            else if(slack[y] > tmp)
                slack[y] = tmp;
        }
        return false;
    }
    int KM(){
        memset(linker,-1,sizeof(linker));
        memset(ly,0,sizeof(ly));
        for(int i = 0;i < nx;i++){
            lx[i] = -INF;
            for(int j = 0;j < ny;j++){
                if(g[i][j] > lx[i])
                    lx[i] = g[i][j];
            }
        }
        for(int x = 0;x < nx;x++){
            for(int i = 0;i < ny;i++)
                slack[i] = INF;
            while(true){
                memset(visx,false,sizeof(visx));
                memset(visy,false,sizeof(visy));
                if(DFS(x))break;
                int d = INF;
                for(int i = 0;i < ny;i++){
                    if(!visy[i] && d > slack[i])
                        d = slack[i];
                }
                for(int i = 0;i < nx;i++){
                    if(visx[i])
                        lx[i] -= d;
                }
                for(int i = 0;i < ny;i++){
                    if(visy[i])ly[i] += d;
                    else slack[i] -= d;
                }
            }
        }
        int res = 0;
        for(int i = 0;i < ny;i++){
            if(linker[i] != -1)
                res += g[linker[i]][i];
        }
        return res;
    }
    
    int n,m;
    vector<P> house,man;
    char B[300][300];
    char r[400];
    void init(){
        house.clear();man.clear();
    }
    void build(){
        nx=house.size();ny=man.size();
        for(int i=0;i<nx;i++){
            for(int j=0;j<ny;j++){
                g[i][j]=-(abs(house[i].fs-man[j].fs)+abs(house[i].se-man[j].se));
            }
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(scanf("%d%d",&n,&m)&&!(!n&&!m)){
            init();
            for(int i=0;i<n;i++){
                scanf("%s",r);
                for(int j=0;j<m;j++){
                    if(r[j]=='H') house.pb(P(i,j));
                    if(r[j]=='m') man.pb(P(i,j));
                }
            }
            build();
            int ans=KM();
            printf("%d
    ",-ans);
        }
        return 0;
    }
    View Code

    14 Aizu 2251(最小路径覆盖

    题目:有L个请求在t时间把东西送到p地,问最少要几个快递员。

    思路:每个请求拆成两个点,如果从一个点能及时赶到另一个点就建一条边,然后跑二分匹配。。。。。(写好了结果断网,,,然后就这样了吧。。。。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    const int maxn=6000;
    int match[maxn];
    bool used[maxn];
    vector<int> G[maxn];
    bool dfs(int v){
        used[v]=1;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            int w=match[u];
            if(w==-1||!used[w]&&dfs(w)){
                match[v]=u;
                match[u]=v;
                return 1;
            }
        }
        return 0;
    }
    int N,M,L;
    int max_match(){
        memset(match,-1,sizeof match);
        int cnt=0;
        for(int i=1;i<=L*2;i++){
            if(match[i]==-1){
                memset(used,0,sizeof used);
                if(dfs(i)) cnt++;
            }
        }
        return cnt;
    }
    
    int mat[150][150];
    void floyd(){
        for(int k=0;k<N;k++)
            for(int i=0;i<N;i++)
                for(int j=0;j<N;j++)
                    mat[i][j]=min(mat[i][j],mat[i][k]+mat[k][j]);
    }
    P di[2000];
    void build(){
        for(int i=1;i<=L;i++){
            for(int j=1;j<=L;j++){
                if(j==i) continue;
                if(mat[di[i].fs][di[j].fs]<=di[j].se-di[i].se){
                    G[i].pb(j+L);
                    G[j+L].pb(i);
                }
            }
        }
    }
    void init(){
        for(int i=0;i<maxn;i++)
            G[i].clear();
        memset(mat,0x3f,sizeof mat);
        for(int i=0;i<150;i++)
            mat[i][i]=0;
    }
    int main(){
        ////freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(scanf("%d%d%d",&N,&M,&L)&&!(!N&&!M&&!L)){
            init();
            for(int i=0;i<M;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                mat[x][y]=z;
                mat[y][x]=z;
            }
            floyd();
            for(int i=1;i<=L;i++)
                scanf("%d%d",&di[i].fs,&di[i].se);
            build();
            int ans=max_match();
            printf("%d
    ",L-ans);
        }
        return 0;
    }
    View Code

     15 poj 3068(费用流

    题目:求s到t的两条最短不相交路径。

    思路:费用流裸题,拆点跑即可。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    const int MAXV=1e5+300;
    int V;
    const int s=MAXV-1,t=MAXV-2;
    struct EDGE{
        int to,cap,cost,next;
    }ES[MAXV*10];
    int eh;
    int h[MAXV];
    int dis[MAXV];
    int prevv[MAXV],preve[MAXV];
    int head[MAXV];
    void addedge(int from,int to,int cap,int cost){
        ES[eh].to=to;ES[eh].cap=cap;ES[eh].cost=cost;
        ES[eh].next=head[from];head[from]=eh++;
        ES[eh].to=from;ES[eh].cap=0;ES[eh].cost=-cost;
        ES[eh].next=head[to];head[to]=eh++;
    }
    ll min_cost_flow(int s,int t,int f){
        V=MAXV;//default V size maxed
        ll res=0;
        memset(h,0,sizeof h);
        while(f>0){
            priority_queue<P,vector<P> ,greater<P> >Q;////Dijkstra计算势h
            fill(dis,dis+V,INF);
            dis[s]=0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p=Q.top();Q.pop();
                int v=p.se;
                if(dis[v]<p.fs) continue;
                for(int i=head[v];i!=-1;i=ES[i].next){
                    EDGE &e=ES[i];
                    if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                        dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        Q.push(P(dis[e.to],e.to));
                    }
                }
            }
            if(dis[t]==INF){
                return -1;
            }
            for(int v=0;v<V;v++){
                h[v]+=dis[v];
            }
            int d=f;
            for(int v=t;v!=s;v=prevv[v]){
                d=min(d,ES[preve[v]].cap);
            }
            f-=d;
            res+=d*h[t];
            for(int v=t;v!=s;v=prevv[v]){
                EDGE &e=ES[preve[v]];
                e.cap-=d;
                ES[preve[v]^1].cap+=d;
            }
        }
        return res;
    }
    void clear_G(){
        memset(head,-1,sizeof head);
    }
    ////end
    
    int N,M;
    int cas;
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(cin>>N>>M,!(!N&&!M)){
            clear_G();
            for(int i=0;i<M;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                addedge(x+N,y,1,z);
            }
            for(int i=0;i<N;i++){
                addedge(i,i+N,1,0);
            }
            int ans=min_cost_flow(N,N-1,2);
            if(ans==-1){
                printf("Instance #%d: Not possible
    ",++cas);
            }else{
                printf("Instance #%d: %d
    ",++cas,ans);
            }
        }
        return 0;
    }
    View Code

     16 poj 3422(费用流

    题目:给出一个矩阵,每个格子上有些钱,每次只能向下或向右走,问走k次最多能拿到多少钱。

    思路:拆点,然后建一条费用为1的边,再建一条费用为INF的边,即可保证每个点只走一次。然后跑流量为k的费用流。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    const int MAXV=1e5+300;
    int V;
    const int s=MAXV-1,t=MAXV-2;
    struct EDGE{
        int to,cap,cost,next;
    }ES[MAXV*10];
    int eh;
    int h[MAXV];
    int dis[MAXV];
    int prevv[MAXV],preve[MAXV];
    int head[MAXV];
    void addedge(int from,int to,int cap,int cost){
        ES[eh].to=to;ES[eh].cap=cap;ES[eh].cost=cost;
        ES[eh].next=head[from];head[from]=eh++;
        ES[eh].to=from;ES[eh].cap=0;ES[eh].cost=-cost;
        ES[eh].next=head[to];head[to]=eh++;
    }
    ll min_cost_flow(int s,int t,int f){
        V=MAXV;//default V size maxed
        ll res=0;
        memset(h,0,sizeof h);
        while(f>0){
            priority_queue<P,vector<P> ,greater<P> >Q;////Dijkstra计算势h
            fill(dis,dis+V,INF);
            dis[s]=0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p=Q.top();Q.pop();
                int v=p.se;
                if(dis[v]<p.fs) continue;
                for(int i=head[v];i!=-1;i=ES[i].next){
                    EDGE &e=ES[i];
                    if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                        dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        Q.push(P(dis[e.to],e.to));
                    }
                }
            }
            if(dis[t]==INF){
                return -1;
            }
            for(int v=0;v<V;v++){
                h[v]+=dis[v];
            }
            int d=f;
            for(int v=t;v!=s;v=prevv[v]){
                d=min(d,ES[preve[v]].cap);
            }
            f-=d;
            res+=d*h[t];
            for(int v=t;v!=s;v=prevv[v]){
                EDGE &e=ES[preve[v]];
                e.cap-=d;
                ES[preve[v]^1].cap+=d;
            }
        }
        return res;
    }
    void clear_G(){
        memset(head,-1,sizeof head);
    }
    ////end
    
    int N,K;
    int cas;
    int mat[1000][1000];
    void build(){
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                addedge(i*N+j,i*N+j+N*N,1,-mat[i][j]);
                addedge(i*N+j,i*N+j+N*N,INF,0);
                if(i<N-1) addedge(i*N+j+N*N,(i+1)*N+j,INF,0);
                if(j<N-1) addedge(i*N+j+N*N,i*N+j+1,INF,0);
            }
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        while(cin>>N>>K){
            clear_G();
            for(int i=0;i<N;i++){
                for(int j=0;j<N;j++){
                    scanf("%d",&mat[i][j]);
                }
            }
            build();
            int ans=min_cost_flow(0,(N-1)*N+N-1+N*N,K);
            printf("%d
    ",-ans);
        }
        return 0;
    }
    View Code

     17 poj3680(费用流

    题目:给出若干带权区间,要求在任意一个点不被超过k个区间覆盖的情况下总的权值和最大。

    思路:可以用费用流巧妙地解决这个区间选择的问题。首先把所有端点排序,然后依次从前一个点到后一个点连边。对于一个区间,从起始端点向区间终点连一条容量为1费用为权值负数的边。显然,对于任意区间,如果有流量流过,对应选择了这个区间。对于一个点,如果选择了k个覆盖这个点的区间,那么就不会有流量到达这个点,符合题目要求。

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    typedef pair<ll,int> D;
    
    
    const int MAXV=500;
    int V;
    const int s=MAXV-1,t=MAXV-2;
    struct EDGE{
        int to,cap,cost,next;
    }ES[MAXV*10];
    int eh;
    int h[MAXV];
    int dis[MAXV];
    int prevv[MAXV],preve[MAXV];
    int head[MAXV];
    void addedge(int from,int to,int cap,int cost){
        ES[eh].to=to;ES[eh].cap=cap;ES[eh].cost=cost;
        ES[eh].next=head[from];head[from]=eh++;
        ES[eh].to=from;ES[eh].cap=0;ES[eh].cost=-cost;
        ES[eh].next=head[to];head[to]=eh++;
    }
    bool inq[MAXV];
    ll min_cost_flow(int s,int t,int f){
        //V=MAXV;//default V size maxed
        ll res=0;
        memset(h,0,sizeof h);
        queue<P> Q;////spfa计算势h
        fill(dis,dis+V,INF);
        dis[s]=0;
        Q.push(P(0,s));
        inq[s]=1;
        while(!Q.empty()){
            P p=Q.front();Q.pop();
            int v=p.se;
            inq[v]=0;
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                    dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    if(!inq[e.to]) Q.push(P(dis[e.to],e.to)),inq[e.to]=1;
                }
            }
        }
        for(int v=0;v<V;v++)
            h[v]+=dis[v];
        while(f>0){
            priority_queue<P,vector<P> ,greater<P> >Q;////Dijkstra计算势h
            fill(dis,dis+V,INF);
            dis[s]=0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p=Q.top();Q.pop();
                int v=p.se;
                if(dis[v]<p.fs) continue;
                for(int i=head[v];i!=-1;i=ES[i].next){
                    EDGE &e=ES[i];
                    if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                        dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        Q.push(P(dis[e.to],e.to));
                    }
                }
            }
            if(dis[t]==INF) return -1;
            for(int v=0;v<V;v++) h[v]+=dis[v];
            int d=f;
            for(int v=t;v!=s;v=prevv[v])
                d=min(d,ES[preve[v]].cap);
            f-=d;
            res+=d*h[t];
            for(int v=t;v!=s;v=prevv[v]){
                EDGE &e=ES[preve[v]];
                e.cap-=d;
                ES[preve[v]^1].cap+=d;
            }
        }
        return res;
    }
    void clear_G(){
        eh=0;
        memset(head,-1,sizeof head);
    }
    
    const int maxn=300;
    int N,K;
    int a[maxn],b[maxn],w[maxn];
    int dc[maxn*2];
    int hh;
    int main(){
        ///freopen("/home/slyfc/CppFiles/in","r",stdin);
        //freopen("/home/slyfc/CppFiles/out","w",stdout);
        int T;
        cin>>T;
        while(T--){
            cin>>N>>K;
            clear_G();
            for(int i=0;i<N;i++){
                scanf("%d%d%d",&a[i],&b[i],&w[i]);
                dc[i]=a[i],dc[i+N]=b[i];
            }
            sort(dc,dc+N*2);
            hh=unique(dc,dc+N*2)-dc;
            V=hh+1;
            for(int i=1;i<hh;i++)
                addedge(i,i+1,INF,0);
            for(int i=0;i<N;i++){
                a[i]=lower_bound(dc,dc+hh,a[i])-dc+1;
                b[i]=lower_bound(dc,dc+hh,b[i])-dc+1;
            }
            for(int i=0;i<N;i++)
                addedge(a[i],b[i],1,-w[i]);
            int ans=min_cost_flow(1,hh,K);
            printf("%d
    ",-ans);
        }
        return 0;    
    }
    View Code

    用dijkstra优化的费用流是比裸跑spfa要快不少。

    18 SPOJ  BOXES(费用流

    题目:给出一排盒子,里面有若干球,要求用最小的步数让每个盒子里至多有一个球.

    思路:费用流裸题.

    /*
    * @author:  Cwind
    */
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    
    ////链表版
    const int MAXV=1200;
    int V;
    const int s=MAXV-1,t=MAXV-2;
    struct EDGE{
        int to,cap,cost,next;
    }ES[MAXV*10];
    int eh;
    int h[MAXV];
    int dis[MAXV];
    int prevv[MAXV],preve[MAXV];
    int head[MAXV];
    void addedge(int from,int to,int cap,int cost){
        ES[eh].to=to;ES[eh].cap=cap;ES[eh].cost=cost;
        ES[eh].next=head[from];head[from]=eh++;
        ES[eh].to=from;ES[eh].cap=0;ES[eh].cost=-cost;
        ES[eh].next=head[to];head[to]=eh++;
    }
    bool inq[MAXV];
    ll min_cost_flow(int s,int t,int f){
        V=MAXV;//default V size maxed
        ll res=0;
        memset(h,0,sizeof h);
        /*queue<P> Q;////spfa计算势h
        fill(dis,dis+V,INF);
        dis[s]=0;
        Q.push(P(0,s));
        inq[s]=1;
        while(!Q.empty()){
            P p=Q.front();Q.pop();
            int v=p.se;
            inq[v]=0;
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                    dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                    prevv[e.to]=v;
                    preve[e.to]=i;
                    if(!inq[e.to]) Q.push(P(dis[e.to],e.to)),inq[e.to]=1;
                }
            }
        }
        for(int v=0;v<V;v++)
            h[v]+=dis[v];*/
        while(f>0){
            priority_queue<P,vector<P> ,greater<P> >Q;////Dijkstra计算势h,也可裸跑spfa
            fill(dis,dis+V,INF);
            dis[s]=0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p=Q.top();Q.pop();
                int v=p.se;
                if(dis[v]<p.fs) continue;
                for(int i=head[v];i!=-1;i=ES[i].next){
                    EDGE &e=ES[i];
                    if(e.cap>0&&dis[e.to]>dis[v]+e.cost+h[v]-h[e.to]){
                        dis[e.to]=dis[v]+e.cost +h[v]-h[e.to];
                        prevv[e.to]=v;
                        preve[e.to]=i;
                        Q.push(P(dis[e.to],e.to));
                    }
                }
            }
            if(dis[t]==INF) return -1;
            for(int v=0;v<V;v++) h[v]+=dis[v];
            int d=f;
            for(int v=t;v!=s;v=prevv[v])
                d=min(d,ES[preve[v]].cap);
            f-=d;
            res+=d*h[t];
            for(int v=t;v!=s;v=prevv[v]){
                EDGE &e=ES[preve[v]];
                e.cap-=d;
                ES[preve[v]^1].cap+=d;
            }
        }
        return res;
    }
    void clear_G(){
        eh=0;
        memset(head,-1,sizeof head);
    }
    
    const int maxn=1005;
    int n,T;
    int a[maxn];
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        //freopen("/home/slyfc/CppFiles/out","w",stdout);
        cin>>T;
        while(T--){
            clear_G();
            scanf("%d",&n);
            int sum=0;
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                sum+=a[i];
            }
            for(int i=1;i<n;i++){
                addedge(i,i+1,INF,1);
            }
            for(int i=2;i<=n;i++){
                addedge(i,i-1,INF,1);
            }
            addedge(n,1,INF,1);
            addedge(1,n,INF,1);
            for(int i=1;i<=n;i++){
                addedge(s,i,a[i],0);
                addedge(i,t,1,0);
            }
            int ans=min_cost_flow(s,t,sum);
            printf("%d
    ",ans);
        }
        return 0;    
    }
    View Code

     19 SGU 185(费用流

    题目:要求两条从s到t的最短路径,并输出.

    思路:sgu卡常数简直sxbk......而且这题是卡空间........首先上去就是费用流然后直接mle,后来又改成先最短路然后再dinic还是mle,最后把dinic的图用链表存才过......还要注意的一点是输出,要有流量并且保证方向正确.....其实这题如果不是先做最短路的话输出似乎还比较麻烦.....

    /*
    * @author:  Cwind
    */
    
    ///#pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    
    using namespace std;
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    
    const int maxv=405;
    int mat[maxv][maxv];
    int dis[maxv];
    int N,M;
    int dij(){
        fill(dis,dis+maxv,INF);
        priority_queue<P,vector<P>,greater<P> > Q;
        Q.push(P(0,1));
        dis[1]=0;
        while(!Q.empty()){
            int v=Q.top().se,d=Q.top().fs;Q.pop();
            if(dis[v]<d) continue;
            for(int i=1;i<=N;i++){
                if(dis[i]>dis[v]+mat[i][v]){
                    dis[i]=dis[v]+mat[i][v];
                    Q.push(P(dis[i],i));
                }
            }
        }
        return dis[N];
    }
    
    const int MAXV=405;
    const int MAXE=MAXV*MAXV;
    struct EDGE{
        int to,cap,next;
    }ES[MAXE];
    int head[MAXV];
    int eh;
    void addedge(int from,int to,int cap){///加边
        ES[eh].to=to,ES[eh].cap=cap,ES[eh].next=head[from];
        head[from]=eh++;
        ES[eh].to=from,ES[eh].cap=0,ES[eh].next=head[to];
        head[to]=eh++;
    }
    int s=MAXV-1;
    int t=MAXV-2;
    int level[MAXV];
    queue<int> Q;
    void bfs(int s){////bfs出分层图
        memset(level,-1,sizeof level);
        level[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();Q.pop();
            for(int i=head[v];i!=-1;i=ES[i].next){
                EDGE &e=ES[i];
                if(e.cap>0&&level[e.to]==-1){
                    level[e.to]=level[v]+1;
                    Q.push(e.to);
                }
            }
        }
    }
    int iter[MAXV];
    int dfs(int v,int t,int f){///dfs寻找增广路径
        if(v==t) return f;
        for(int &i=iter[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(e.cap>0&&level[e.to]>level[v]){
                int d=dfs(e.to,t,min(f,e.cap));
                if(d>0){
                    e.cap-=d;
                    ES[i^1].cap+=d;
                    return d;
                }
            }
        }
        return 0;
    }
    int dinic(int s,int t){///dinic算法求解最大流
        int flow=0;
        for(;;){
            bfs(s);
            if(level[t]==-1) return flow;
            for(int i=0;i<MAXV;i++) iter[i]=head[i];
            int f;
            while((f=dfs(s,t,INF))>0) flow+=f;
        }
        return 0;
    }
    void dinic_init(){
        memset(head,-1,sizeof head);
        eh=0;
    }
    
    void build(){
        for(int i=1;i<=N;i++){
            for(int j=1;j<=N;j++){
                if(dis[j]==dis[i]+mat[i][j]) addedge(i,j,1);
            }
        }
    }
    
    vector<int> rout;
    void out(int v){
        rout.pb(v);
        if(v==1) return;
        for(int i=head[v];i!=-1;i=ES[i].next){
            EDGE &e=ES[i];
            if(!e.cap||(i&1)==0) continue;
            e.cap=0;
            out(e.to);
            break;
        }
    }
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        dinic_init();
        memset(mat,0x3f,sizeof mat);
        cin>>N>>M;
        for(int i=0;i<M;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            mat[x][y]=z;
            mat[y][x]=z;
        }
        int mindis=dij();
        build();
        int maxflow=dinic(1,N);
        if(mindis>1e9||maxflow<2){
            puts("No solution");
        }else{
            out(N);
            for(int i=rout.size()-1;i>=0;i--) printf("%d ",rout[i]);
            puts("");
            rout.clear();
            out(N);
            for(int i=rout.size()-1;i>=0;i--) printf("%d ",rout[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    oschina 终端/远程登录
    oschina文档/文本编辑
    oschinaIM/聊天/语音工具
    oschina浏览器开发
    oschina P2P/BT开源软件
    oschina图形和图像工具开源软件
    java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
    java之jvm学习笔记三(Class文件检验器)
    手把手教popupWindow从下往上,以达到流行效果
    java实现代理domino web邮件下载
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4858067.html
Copyright © 2020-2023  润新知