[最大流] POJ1087 ZOJ1157 A Plug for UNIX

看了几天最大流,还是最喜欢Dinic,比较清晰,下午写了一般预流推进,结构也比较简单,网络流算法真是多。

晚上自己写的第一道网络流,WA了不知道多少次,果然是建图错了,算法没写错,果然网络流建完图就AC一半。

刚开始建图的时候一直把设备的名字无视掉了,以为没用,其实不然。

因为一个设备显然只能插一个插头,所以用设备来连接汇点,中间的各种都要受到最后设备的容量(1)约束,一个设备只能流出1个单位,然后把源点连接到插头,注意插头可能会重复所以用+=1,最后转换器的容量无限大,因为可以无限转换,把转换的连边,这样求最大流才对,还是要学习啊。

贴个代码纪念不易的AC。

ZOJ的输入第一行是测试组数,改一下就行。

#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define LL long long in
#define INF 0x7fffffff
using namespace std;
map<string, int>mp;
int mat[1005][1005];
int lev[10005];
int plu, fac, trans, cnt;
int fir[20005], nex[20005];
int U[20005], V[20005], ecnt;
void add(int a, int b){
    U[ecnt] = a, V[ecnt] = b;
    nex[ecnt] = fir[a];
    fir[a] = ecnt ++;
    U[ecnt] = b, V[ecnt] = a;
    nex[ecnt] = fir[b];
    fir[b] = ecnt++;
}
bool Bfs(int s,int t){
    memset(lev, -1, sizeof(lev));
    queue<int>q;
    q.push(s); lev[s] = 0;
    while( !q.empty() ){
        int u = q.front(); q.pop();
        for(int k = fir[u]; k != -1; k = nex[k]){
            int v = V[k];
            if(mat[u][v] && lev[v] == -1){
                lev[v] = lev[u] + 1;
                q.push(v);
            }
        }
    }
    return lev[t] > 0;
}
int Dfs(int s, int t, int low){
    if( s == t ) return low;
    int a = 0;
    for(int k = fir[s]; k != -1; k = nex[k]){
        int v = V[k];
        if( mat[s][v] && lev[v] == lev[s] + 1 && (a = Dfs(v, t, min(low, mat[s][v]) ) ) ){
            mat[s][v] -= a;
            mat[v][s] += a;
            return a;
        }
    }
    lev[s] = -1;
    return 0;
}
void Dinic(int s,int t,int n){
    int ans = 0, a;
    while(Bfs(s, t)){
        while( a = Dfs(s, t, INF) ) ans += a;
    }
    printf("%d\n", fac - ans);
}
int main(){
    int T=0, s = 0, t = 1000;
    char p[50], p1[50];
    //scanf("%d", &T);
    while(scanf("%d", &plu) != EOF){
        int tmp, tmp1;
        mp.clear();
        cnt = 1, ecnt = 0;
        memset(fir, -1, sizeof(fir));
        memset(mat, 0, sizeof(mat));
        for(int i = 0; i < plu; ++i){
            scanf("%s", p);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( !mat[s][tmp] ){
                add(s, tmp);
            }
            mat[s][tmp] += 1;
        }
        scanf("%d%*c", &fac);
        for(int i = 0; i < fac; ++i){
            scanf("%s%s", p1, p);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( (tmp1=mp[p1]) == 0) tmp1 = mp[p1] = cnt++;
            mat[tmp1][tmp] += 1;
            mat[tmp][t] += 1;
            add(tmp1, tmp);
            add(tmp, t);
        }
        scanf("%d%*c", &trans);
        for(int i = 0; i < trans; ++i){
            scanf("%s%s", p, p1);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( (tmp1=mp[p1]) == 0 ) tmp1 = mp[p1] = cnt++;
            mat[tmp1][tmp] = INF;
            add(tmp1, tmp);
        }
        Dinic(s, t, cnt);
    }
}

再贴一个一般预流推进,顺便写了一发熟悉算法结构。

#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define LL long long in
#define INF 0x7fffffff
using namespace std;
map<string, int>mp;
int mat[1005][1005];
int plu, fac, trans, cnt;
int fir[20005], nex[20005];
int U[20005], V[20005], ecnt;
int dis[1005], ef[1005]; //距离标号 盈余
queue<int>q;
void add(int a, int b){
    U[ecnt] = a, V[ecnt] = b;
    nex[ecnt] = fir[a];
    fir[a] = ecnt ++;
    U[ecnt] = b, V[ecnt] = a;
    nex[ecnt] = fir[b];
    fir[b] = ecnt++;
}
void push(int s, int t, int u,int &ans){
    int v, p;
    for(int k = fir[u]; k != -1; k = nex[k]){
        v = V[k], p = min(mat[u][v], ef[u]);
        if( p && (u == s || dis[u] == dis[v] + 1)){
            mat[u][v] -= p, mat[v][u] += p;
            ef[u] -= p, ef[v] += p;
            if( v == t) ans += p;
            if( v != s && v!=t ) q.push(v);
        }
    }
}
void relabel(int s, int t, int u){
    if(u != s && u != t && ef[u]){
        dis[u]+=1;
        q.push(u);
    }
}
void push_relabel(int s, int t, int n){
    int ans = 0;
    memset(dis, 0, sizeof(dis));
    dis[s] = n;
    ef[s] = INF, ef[t] = -INF;
    q.push(s);
    int u;
    while(!q.empty()){
        u = q.front(); q.pop();
        push(s, t, u, ans);
        relabel(s, t, u);
    }
    printf("%d\n", fac - ans);
}
int main(){
    int T=0, s = 0, t = 1000;
    char p[50], p1[50];
    while( scanf("%d", &plu) != EOF ){

        int tmp, tmp1;
        mp.clear();
        cnt = 1, ecnt = 0;
        memset(fir, -1, sizeof(fir));
        memset(mat, 0, sizeof(mat));
        for(int i = 0; i < plu; ++i){
            scanf("%s", p);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( !mat[s][tmp] ){
                add(s, tmp);
            }
            mat[s][tmp] += 1;
        }
        scanf("%d%*c", &fac);
        for(int i = 0; i < fac; ++i){
            scanf("%s%s", p1, p);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( (tmp1=mp[p1]) == 0) tmp1 = mp[p1] = cnt++;
            mat[tmp1][tmp] += 1;
            mat[tmp][t] += 1;
            add(tmp1, tmp);
            add(tmp, t);
        }
        scanf("%d%*c", &trans);
        for(int i = 0; i < trans; ++i){
            scanf("%s%s", p, p1);
            if( (tmp=mp[p]) == 0) tmp = mp[p] = cnt++;
            if( (tmp1=mp[p1]) == 0 ) tmp1 = mp[p1] = cnt++;
            mat[tmp1][tmp] = INF;
            add(tmp1, tmp);
        }
        push_relabel(s, t, cnt);
        if(T) puts("");
    }
}


你可能感兴趣的:(ACM,ZOJ,poj,网络流)