题目大意:
给你n个点,并且给你这n个点的网络邻接矩阵,你可以对任意边进行增加流量的操作,但是最多不能超过k,问最大流。
思路:
1、我们首先将原图建到网络中:
设定1为源点,设定n为汇点,将各个边都加入网络中,设定其花费为0,流量为其本身流量。
2、那么我们对将原图建立到网络中跑连续增广路算法求费用流的话,此时费用一定为0,最大流量一定是其原图的最大流,那么剩下可以增加进去的流也可以通过同理来求。
3、那么接下来我们将原图中的每条边再引申出来一条边,设定其花费为1,流量为K,首先保证对应一条边的流量不能增加超过K。然后我们再对这样建图的网络跑费用流,其最大流一定可以包含了原图的最大流,所以这里不必担心原图的最大流会不会加进来的问题。接下来判断什么时候终止,显然,我们在跑完SPFA之后,得到的最短路径值就是增加一单位流的花费,那么我们如果这个花费达到了K我们就终止连续增广路算法即可。
4、这个时候我们就保证了只增加流量为K的情况下的最大流。注意K==0的时候需要特殊判定一下。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
struct node
{
int from;
int to;
int w;
int next;
int num;
int f;
}e[1515151];
int head[1212];
int pre[1212];
int path[1212];
int dis[1212];
int vis[1212];
int n,m,cont,ss,tt,k;
void add(int from,int to,int f,int w)
{
e[cont].num=cont;
e[cont].f=f;
e[cont].w=w;
e[cont].to=to;
e[cont].next=head[from];
head[from]=cont++;
}
int SPFA()
{
queue<int >s;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f;
dis[ss]=0;
s.push(ss);
while(!s.empty())
{
int u=s.front();
s.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
int f=e[i].f;
if(f&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=u;
path[v]=e[i].num;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(dis[tt]==0x3f3f3f3f)return 0;
else return 1;
}
void MCMF()
{
int maxflow=0;
int ans=0;
while(SPFA()==1)
{
int minn=0x3f3f3f3f;
for(int i=tt;i!=ss;i=pre[i])
{
minn=min(minn,e[path[i]].f);
}
for(int i=tt;i!=ss;i=pre[i])
{
e[path[i]].f-=minn;
e[path[i]^1].f+=minn;
}
if(k==0)
{
maxflow+=minn;
continue;
}
if(ans+minn*dis[tt]>k)
{
maxflow+=(k-ans)/dis[tt];
break;
}
ans+=minn*dis[tt];
maxflow+=minn;
if(ans==k)break;
}
printf("%d\n",maxflow);
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
cont=0;
ss=1;
tt=n;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int tmp;
scanf("%d",&tmp);
if(tmp==0)continue;
else
{
add(i,j,tmp,0);
add(j,i,0,0);
add(i,j,k,1);
add(j,i,0,-1);
}
}
}
MCMF();
}
}