网络流汇总....

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\n",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\n");
            continue;
        }
        G[ss].clear();G[tt].clear();
        int res2=dinic(s,t);
        printf("%d\n",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\n",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\n",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\n",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\n",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\n",++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\n",++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\n",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\n",-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\n",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\n",++cas);
        }else{
            printf("Instance #%d: %d\n",++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\n",-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\n",-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\n",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

 

posted @ 2015-10-06 23:58  PlusSeven  阅读(224)  评论(0编辑  收藏  举报