Description
You should find out the minimum cost to transport all the goods safely.
Input
Output
Sample Input
2 1 2 1 2 1 2 2 1 2 1 2 1 1 2 2 2 1 2 1 2 1 2 2 2
Sample Output
4 -1 3
题意描述:一个人携带k单位的东西要从城市1安全到达n,有m条有向的路径连接这n个城市,该人从每条路上经过时可能会遇到劫匪,那么这条路的危险系数为a,那么他要安全的经过该条路径,就需要花a*x*x的费用去雇佣guard(这里x表示该人携带的多少单位的物品),且每条路径上的最多可以携带c单位的物品通过(注意这里c<=5),现在要求最少的费用使他能够安全到达n,若不能到达则输出-1;
分析:该题是显然的费用流题目的变形,因为这里容量变成了x*x了,那么这就用最小费流求出来的值将是错误的,因为2*2!=1*1+1*1的,所以这里我就想到了这些走过的边必须得整体考虑,这里我就先用费用流求出了最大流,让后再在结果中寻找容量改变了的边,然后计算出中的花费,显然这也是错误的,因为第三个样例就果断悲剧了,因为该人走的时候每次并不是选择单位费用最少的那条路走,而是要选择c*x*x的最小的那条边走,所以这样求出来的值是错的,这时候我猛然发现c<=5这个条件没有用,这里我就想到了拆边,若要体现每次都是选择都是在前面选择的基础上进行的,每次求的增广路都是c*x*x代表的权值中最小的,那么基本思路就出来了,将每条容量为w的边拆成容量为1的w条边,这里费用为0的边,只需要建一条边即可,因为这条边不管携带多少单位的东西经过不需要任何费用也是安全的,最后新建一个源点和节点1相连容量为k,费用为0,那么求最小费用最大流即是解,现在剩下的问题就是权值问题了,刚开始我将每条拆开的权值设为c*j*j,这样建图之后用费用流求出最大流后,先判断是否能全部运过去,这里原先有m条边,那么就被拆成了m组边,我想用最小费用流之后在每一组边中找到容量为0且费用最高的那条边然后每组求和,这样也是错的,因为当用最短路进行增广的时候,选择路径的时候就可能不是最好的,因为该边开始已径流过i次了,那么第i+1次流过的费用就应该是(i+1)^2-(i*i),但是我这里的权值却是(i+1)^2,那么在选择路径增广的时候就有可能出现两条边的x*x+y*y<(i+1)^2但是(x*x)-(x-1)^2+(y*y)-(y-1)^(y-1)>(i+1)^2-(i*i),那么这个时候选择错误!!!!!
建图的方法: 新建源点,源点到1连边容量为k,费用为0,将给出的每条边拆成w条容量为1的边每一条的费用为((i+1)^2-(i*i))*c=(2*i-1)*c,费用为0的边不需要拆边,那么这样建图之后求最小费最大流即可,若最大流<k那么表示不能够到达n,则输出-1,否则输出最小费用,注意这里当k=0时,假如图不是连通的,那么则应该输出-1,但是按以上方法输出的为0,我试了一下没有这样的数据!!
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int head[2000],vis[2000],dis[2000],pre[2000];
int cnt,s,T,ans,ss;
struct node
{
int u,v,w,f,next;
} edge[50000];
void add(int u,int v,int w,int f)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].f=f;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].u=v;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].f=-f;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int SPFA()
{
int i;
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
for(i=0; i<=T; i++)
dis[i]=INF;
queue<int>q;
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
i=head[u];
vis[u]=0;
while(i!=-1)
{
if(edge[i].w>0&&dis[edge[i].v]>dis[u]+edge[i].f)
{
dis[edge[i].v]=dis[u]+edge[i].f;
pre[edge[i].v]=i;
if(!vis[edge[i].v])
{
vis[edge[i].v]=1;
q.push(edge[i].v);
}
}
i=edge[i].next;
}
}
if(pre[T]==-1)
return 0;
return 1;
}
void MincostMaxFlow()
{
ans=0,ss=0;
while(SPFA())
{
int maxl=INF;
int p=pre[T];
while(p!=-1)
{
maxl=min(maxl,edge[p].w);
p=pre[edge[p].u];
}
p=pre[T];
while(p!=-1)
{
edge[p].w-=maxl;
edge[p^1].w+=maxl;
p=pre[edge[p].u];
}
ss+=maxl;
ans+=maxl*dis[T];
}
}
int main()
{
int n,m,k;
int x,y,c,w;
while(scanf("%d %d %d",&n,&m,&k)!=EOF)
{
memset(head,-1,sizeof(head));
cnt=0;
for(int i=0;i<m;i++)
{
scanf("%d %d %d %d",&x,&y,&c,&w);
if(c==0)
add(x,y,w,0);
else
{
for(int j=1;j<=w;j++)
add(x,y,1,(2*j-1)*c);
}
}
s=0;
T=n;
add(s,1,k,0);
MincostMaxFlow();
if(ss<k)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}