题目链接:http://poj.org/problem?id=1459
题意:有N个电站,M条线路,P个发电站,C个用电站,(N-P-C)个中转站,题目先给出M条线路的情况,格式如下:(起点,终点)最大流量。然后是发电站和用电站的情况,格式为(电站序号)最大发电量或用电量。求最大消耗的电能。
思路:我们可以设置一个超级源点和一个超级汇点,源点与所有发电站相连,最大流量为发电站的发电量,汇点与所有用电站相连,最大流量为用电站最大用电量,然后用EK算法求最大流即可。另外,题目的读入格式略有点恶心,需要小心read()表示不知道你在说些什么
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=505,INF=1e10;
int N,P,C,M,tot,ed,hed,til,map[maxn][maxn],fa[maxn],que[maxn];
bool vis[maxn];
inline int read() {
int ret=0,f=1;char ch=getchar();
for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
return ret*f;
}
inline int EK() {
// 一定要用BFS来求增广路,用DFS的求法叫FF算法,虽然同样是O(N*M^2)但EK更快,不会超时。
int ans=0;
for (; ; ) {
memset(fa,-1,sizeof fa);
memset(vis,0,sizeof vis);
hed=0,til=1;
que[1]=0,vis[0]=0;
while (hed<til) {
int t=que[++hed];
if (t==ed) break;
for (int i=1; i<=ed; i++) if (!vis[i]&&map[t][i])
fa[i]=t,vis[i]=1,que[++til]=i;
}
if (!vis[ed]) return ans;
int minv=INF;
for (int i=ed; i; i=fa[i]) minv=min(minv,map[fa[i]][i]);
for (int i=ed; i; i=fa[i]) map[fa[i]][i]-=minv,map[i][fa[i]]+=minv;
ans+=minv;
}
}
int main() {
while (~scanf("%lld%lld%lld%lld",&N,&P,&C,&M)) {
tot=0,ed=N+1;
memset(map,0,sizeof map);
for (int i=1; i<=M; i++) {
int x=read()+1,y=read()+1,z=read();
map[x][y]=z;
}
for (int i=1; i<=P; i++) {
int y=read()+1,z=read();
map[0][y]=z;
}
for (int i=1; i<=C; i++) {
int x=read()+1,z=read();
map[x][ed]=z;
}
printf("%d\n",EK());
}
return 0;
}