#include <stdio.h>
int main()
{
puts("转载请注明出处谢谢");
puts("http://blog.csdn.net/vmurder/article/details/43025375");
}
【BZOJ2324】营救皮卡丘 这道题也是一道有下界的最小费用最大流。
我的题解地址:http://blog.csdn.net/vmurder/article/details/41378979
这道题其实就是模板题。
我的处理方法就是把每条边拆一条流量为1的出来,然后费用为本来费用-inf。而在建图时可以把这些扣掉的inf加回来。可以证明这种方法至少在拓扑图上是不会被卡出负环的。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 500
#define M 31000
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3fll
using namespace std;
struct KSD
{
int u,v,len,next;
long long fee;
}e[M];
int head[N],cnt;
void add(int u,int v,int len,int fee)
{
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].len=len;
e[cnt].fee=fee;
e[cnt].next=head[u];
head[u]=cnt;
}
int s,t;
long long dist[N];
int pre[N],lim[N];
bool in[N];
queue<int>q;
void spfa()
{
memset(dist,0x3f,sizeof(dist));
memset(lim,0,sizeof(lim));
while(!q.empty())q.pop();
int i,u,v;
dist[s]=0,in[s]=1;
lim[s]=inf;
q.push(s);
while(!q.empty())
{
u=q.front(),q.pop(),in[u]=0;
for(i=head[u];i;i=e[i].next)
{
v=e[i].v;
if(!e[i].len)continue;
if(dist[v]>dist[u]+e[i].fee)
{
dist[v]=dist[u]+e[i].fee;
lim[v]=min(e[i].len,lim[u]);
pre[v]=i;
if(!in[v])
{
in[v]=1;
q.push(v);
}
}
}
}
return ;
}
void handle(int flow)
{
for(int i=pre[t];i;i=pre[e[i].u])
{
e[i].len-=flow;
e[i^1].len+=flow;
}
}
long long minfee;
int n,m;
void build()
{
int i,j,k;
int a,b,c;
cnt=1;
scanf("%d",&n);
s=n+1,t=n+2;
add(s,1,inf,0),add(1,s,0,0);
for(i=1;i<=n;i++)
{
scanf("%d",&a);
add(i,t,inf,0),add(t,i,0,0);
while(a--)
{
scanf("%d%d",&b,&c);
minfee+=inf;
add(i,b,inf,c),add(b,i,0,-c);
add(i,b,1,c-inf),add(b,i,0,inf-c);
}
}
return ;
}
void checkedge()
{
for(int u=1;u<=t;u++)
{
printf("From %d:",u);
for(int i=head[u];i;i=e[i].next)
{
printf(" %d/%d/%d",e[i].v,e[i].len,e[i].fee);
}
puts("");
}
puts("");
}
int main()
{
freopen("test.in","r",stdin);
build();
while(spfa(),dist[t]<INF)
{
minfee+=dist[t]*lim[t];
handle(lim[t]);
}
cout<<minfee<<endl;
return 0;
}