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