题目大意:网络图中有n个结点,其中有np个发电站,nc个耗电站,还有n-np-nc个中转站,给出m条输电线,每个输电线上的运送电量为l(u,v),意为uv结点间的输电量,p(u)代表u结点的产电量,c(u)代表u结点的耗电量,s(u)代表给u结点的供电量,d(u)=s(u)+p(u)-c(u),代表能从u结点输出的电量,规定发电站的c(u)=0,耗电站的p(u)=0,中转站的p(u)=c(u)=0。问所有耗电站总耗电的最大值。
输入:(可以有很多个case)
n np nc m (u,v)lmax(u,v)(共m个) (u)pmax(u)(共np个) (u)cmax(u)(共nc个)
输出:最大耗电量
分析:最大流的增广路算法(EK算法即最短路径增广算法)。
增广路定理:网络达到最大流<=>残留网络中没有增广路
如何找增广路:bfs搜索找出这样的路径,路径上每一条边都要满足容量-流量>0
找出增广路上容量的最小值,将每条边的容量都减去这个值,并且在增广路上的每条反向边也要加上这个值(为了做到这个bfs时要记录前驱),要求的最大流也加上这个值。最终找不到增广路时就得出了最大流。
代码:转载自http://124654439.iteye.com/blog/2101140
- #include<iostream>
- #include<queue>
- using namespace std;
- #define MAXSIZE 130
- int map[MAXSIZE][MAXSIZE];
- int pre[MAXSIZE];
- queue<int>que;
- int n,np,nc,m;
- int bfs(int src,int dec)//源点和汇点
- {
- memset(pre,-1,sizeof(pre));
- while(!que.empty())que.pop();
- pre[src]=src;
- que.push(src);
- int temp;
- while(!que.empty())
- {
- temp=que.front();
- que.pop();
- if(temp==dec)
- break;
- for(int i=0;i<n+2;i++)
- {
- if(map[temp][i]&&pre[i]==-1)//如果有路径 并且 还没有用过
- {
- pre[i]=temp;
- que.push(i);
- }
- }
- }
- if(temp==dec)
- return 1;
- else
- return 0;
- }
- int maxFlow(int src,int dec)
- {
- int ans=0;
- while(bfs(src,dec))
- {
- int i;
- int min=999999;
- for(i=dec;i!=src;i=pre[i])
- {
- min=min>map[pre[i]][i]?map[pre[i]][i]:min;
- }
- for(i=dec;i!=src;i=pre[i])
- {
- map[pre[i]][i]-=min;
- map[i][pre[i]]+=min;
- }
- ans+=min;
- }
- return ans ;
- }
- int main()
- {
- int i;
- char ss[50];
- int a,b,c;
- int src,dec;
- while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
- {
- memset(map,0,sizeof(map));
- src=n;
- dec=n+1;
- for(i=0;i<m;i++)
- {
- scanf("%s",ss);
- sscanf(ss,"(%d,%d)%d",&a,&b,&c);
- map[a][b]=c;
- }
- for(i=0;i<np;i++)
- {
- scanf("%s",ss);
- sscanf(ss,"(%d)%d",&a,&b);
- map[src][a]=b;
- }
- for(i=0;i<nc;i++)
- {
- scanf("%s",ss);
- sscanf(ss,"(%d)%d",&a,&b);
- map[a][dec]=b;
- }
- printf("%d\n",maxFlow(src,dec));
- }
- return 0;
- }