Transportation
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2670 Accepted Submission(s): 1157
Problem Description
There
are N cities, and M directed roads connecting them. Now you want to
transport K units of goods from city 1 to city N. There are many robbers
on the road, so you must be very careful. The more goods you carry, the
more dangerous it is. To be more specific, for each road i, there is a
coefficient ai. If you want to carry x units of goods along this road, you should pay ai * x2 dollars to hire guards to protect your goods. And what’s worse, for each road i, there is an upper bound Ci, which means that you cannot transport more than Ci units of goods along this road. Please note you can only carry integral unit of goods along each road.
You should find out the minimum cost to transport all the goods safely.
Input
There
are several test cases. The first line of each case contains three
integers, N, M and K. (1 <= N <= 100, 1 <= M <= 5000, 0
<= K <= 100). Then M lines followed, each contains four integers
(ui, vi, ai, Ci), indicating there is a directed road from city ui to vi, whose coefficient is ai and upper bound is Ci. (1 <= ui, vi <= N, 0 < ai <= 100, Ci <= 5)
Output
Output
one line for each test case, indicating the minimum cost. If it is
impossible to transport all the K units of goods, output -1.
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
Source
题意:现在有一个人要从1号点运送k个单位的货物到n号点,每一条边都有一个系数a,从第i条边运送x个单位的货物所需的费用是 ai*x*x,第i条边有个容量上限Ci,问运送这k个单位的货物所需的最小费用,如果不能运送,输出-1。
题解:参考自刘汝佳的<算法竞赛-训练指南>,由于每个边的容量上限不会超过5,而我们每次运送的也是整数,所以可以利用拆边来表示一条容量为Ci的边能够运送的所有可能,假设Ci==5,那么拆成5条容量为1的边,费用分别为 1*ai,3*ai,5*ai,7*ai,9*ai,那么所有的 x*x 都可以由这几条边组合而成,然后设定超级源点和1号点的容量为 k,n号点和超级汇点的容量为k ,这样的话就限制了最大流不会超过k.然后跑一遍MCMF,判断一下maxflow是否为k,是的话,输出mincost,不是的话,输出 -1。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int INF = 999999999; const int N = 200; const int M = 100005; struct Edge{ int u,v,cap,cost,next; }edge[M]; int head[N],tot,low[N],pre[N]; int total ; bool vis[N]; void addEdge(int u,int v,int cap,int cost,int &k){ edge[k].u=u,edge[k].v=v,edge[k].cap = cap,edge[k].cost = cost,edge[k].next = head[u],head[u] = k++; edge[k].u=v,edge[k].v=u,edge[k].cap = 0,edge[k].cost = -cost,edge[k].next = head[v],head[v] = k++; } void init(){ memset(head,-1,sizeof(head)); tot = 0; } bool spfa(int s,int t,int n){ memset(vis,false,sizeof(vis)); for(int i=0;i<=n;i++){ low[i] = INF; pre[i] = -1; } queue<int> q; low[s] = 0; q.push(s); while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = false; for(int k=head[u];k!=-1;k=edge[k].next){ int v = edge[k].v; if(edge[k].cap>0&&low[v]>low[u]+edge[k].cost){ low[v] = low[u] + edge[k].cost; pre[v] = k; ///v为终点对应的边 if(!vis[v]){ vis[v] = true; q.push(v); } } } } if(pre[t]==-1) return false; return true; } int MCMF(int s,int t,int n){ int mincost = 0,minflow,flow=0; while(spfa(s,t,n)) { minflow=INF+1; for(int i=pre[t];i!=-1;i=pre[edge[i].u]) minflow=min(minflow,edge[i].cap); flow+=minflow; for(int i=pre[t];i!=-1;i=pre[edge[i].u]) { edge[i].cap-=minflow; edge[i^1].cap+=minflow; } mincost+=low[t]*minflow; } total=flow; return mincost; } int n,m,k; bool flag[N][N]; int main(){ while(scanf("%d%d%d",&n,&m,&k)!=EOF){ init(); memset(flag,-1,sizeof(flag)); int src = 0,des = n+1; for(int i=1;i<=m;i++){ int u,v,a,c; scanf("%d%d%d%d",&u,&v,&a,&c); for(int j=0;j<c;j++){ addEdge(u,v,1,(2*j+1)*a,tot); } } addEdge(src,1,k,0,tot); addEdge(n,des,k,0,tot); int mincost = MCMF(src,des,n+2); if(total<k) printf("-1\n"); else printf("%d\n",mincost); } }