[最大流] POJ1087 ZOJ1157 A Plug for UNIX

来源:互联网 发布:base64.js 怎么解码 编辑:程序博客网 时间:2024/05/16 08:56

看了几天最大流,还是最喜欢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 0x7fffffffusing 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 0x7fffffffusing 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("");    }}


0 0