题目链接:http://poj.org/problem?id=1459
题意:有许多发电厂,需求电的地方(就说耗电场吧)和一些中转站,要求出各个耗电场耗电之和,并使之最大。其中边上的权值为能流通的最大电量。
题目解析:这道题目也是很简单的最大流题目,只需要添加一个总的源点和一个总的汇点,然后从总源点到子源点边上的权值为子源点的发电量,从汇点到总汇点边上的权值为子汇点的需求电量。就转化成了单源点单汇点的最大流问题了。刚学网络流,不成熟的SAP算法,代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 205
#define INS 0xfffffff
#define clr(arr) memset(arr,0,sizeof(arr))
int map[MAXN][MAXN];
int cate[MAXN],index[MAXN],gap[MAXN];
int pre[MAXN],q[MAXN];
bool vis[MAXN],flag;
int minres;
void init_gap_bfs(int n){
int v,start,end,size = 100;
start = end = 0; index[0] = 1; clr(vis); clr(q);
q[start] = n; vis[n] = true; end++;
while(start != end){
v = q[start];
for(int i = 0;i <= n;++i){
if((!vis[i] ) && map[i][v] > 0){
vis[i] = true;
gap[i] = gap[v] + 1;
index[ gap[i] ]++;
q[end] = i; end = (end+1)%size;
}
}
start = (start+1)%size;
}
}
bool dfs(int k,int n){
int m = minres;
for(int i = 0;i <= n;++i)
if(gap[k] - gap[i] ==1 && map[k][i] > 0){
pre[i] = k; minres = min(minres,map[k][i]);
if(i == n || dfs(i,n)) return true;
minres = m;
}
index[ gap[k] ]--; index[ gap[k]+1 ]++;
if(index[ gap[k] ] == 0) flag = true;
gap[k] += 1;
return false;
}
int SAP(int b,int n){
flag = false;
int maxflow = 0;
while(!flag){
clr(pre); pre[0] = -1; minres = INS;
if(!dfs(b,n)) continue;
int i = n; maxflow += minres;
while(pre[i] != -1){
map[ pre[i] ][i] -= minres;
map[i][ pre[i] ] += minres;
i = pre[i];
}
} return maxflow;
}
int main()
{
//freopen("1.txt","r",stdin);
int n,np,nc,m,b,e,v,p;
while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
clr(cate); clr(map); clr(index); clr(gap);
for(int i = 0;i < m;++i){
scanf(" (%d,%d)%d ",&b,&e,&v);
b++; e++;
map[b][e] += v;
}
for(int i = 0;i < np + nc;++i){
scanf(" (%d)%d ",&p,&v); p++;
if(i < np) cate[p] += v;
else cate[p] -=v;
}
for(int i =1;i <= n;++i){
if(cate[i] > 0) map[0][i] = cate[i];
if(cate[i] < 0) map[i][n+1] = -cate[i];
}
init_gap_bfs(n+1);
printf("%d\n",SAP(0,n+1));
}
return 0;
}
下面是用间隙优化和弧优化的代码,不过弧优化没写好,每次当从k点找不到增广路的时候,更新从k点到汇点的距离,是自加1,不是找所有孩子里汇点最近的加1,不知道怎么处理的,提交结果竟然时间一点也没减少。。。。可能是没用邻接表存边的关系吧,参考代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 205
#define INS 0xfffffff
#define clr(arr) memset(arr,0,sizeof(arr))
int map[MAXN][MAXN];
int cate[MAXN],index[MAXN],gap[MAXN];
int pre[MAXN],q[MAXN],stck[MAXN];
bool vis[MAXN],flag;
int minres,top;
void init_gap_bfs(int n){
int v,start,end,size = 100;
start = end = 0; index[0] = 1; clr(vis); clr(q);
q[start] = n; vis[n] = true; end++;
while(start != end){
v = q[start];
for(int i = 0;i <= n;++i){
if((!vis[i] ) && map[i][v] > 0){
vis[i] = true;
gap[i] = gap[v] + 1;
index[ gap[i] ]++;
q[end] = i; end = (end+1)%size;
}
}
start = (start+1)%size;
}
}
bool dfs(int k,int n){
int m = minres,minn = INS;
for(int i = 0;i <= n;++i){
if(gap[k] - gap[i] ==1 && map[k][i] > 0){
pre[i] = k; minres = min(minres,map[k][i]);
if(i != n) stck[++top] = i;
if(i == n || dfs(i,n)) return true;
minres = m;
}
}
index[ gap[k] ]--;
index[ gap[k]+1 ]++;
if(index[ gap[k] ] == 0) flag = true;
gap[k] += 1; top--;
return false;
}
int SAP(int b,int n){
flag = false; top = 0;
int maxflow = 0; stck[top] = b;
while(!flag){
clr(pre); pre[0] = -1; minres = INS;
if(top < 0) top = 0;
if(!dfs(stck[top],n)) continue;
int i = n; maxflow += minres;
while(pre[i] != -1){
map[ pre[i] ][i] -= minres;
map[i][ pre[i] ] += minres;
i = pre[i];
}
top = 0;
} return maxflow;
}
int main()
{
//freopen("1.txt","r",stdin);
int n,np,nc,m,b,e,v,p;
while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
clr(cate); clr(index); clr(gap); clr(stck);
memset(map,-1,sizeof(map));
for(int i = 0;i < m;++i){
scanf(" (%d,%d)%d ",&b,&e,&v);
b++; e++;
if(map[b][e] == -1) map[b][e] = 0;
map[b][e] += v;
}
for(int i = 0;i < np + nc;++i){
scanf(" (%d)%d ",&p,&v); p++;
if(i < np) cate[p] += v;
else cate[p] -=v;
}
for(int i =1;i <= n;++i){
if(cate[i] > 0) map[0][i] = cate[i];
if(cate[i] < 0) map[i][n+1] = -cate[i];
}
init_gap_bfs(n+1);
printf("%d\n",SAP(0,n+1));
}
return 0;
}