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