题目地址:HDU 3667
这题的建图真是巧妙。。。为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行。但是每条边的流量并不是1,该怎么办呢。这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边。但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来。这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此。然后按照给出的边建图跑一次费用流就可以了。
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; int head[300], source, sink, cnt, cost, flow, k; int vis[300], d[300], cur[300]; struct node { int u, v, cap, cost, next; } edge[100000]; void add(int u, int v, int cap, int cost) { edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].cost=cost; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].cost=-cost; edge[cnt].next=head[v]; head[v]=cnt++; } int spfa() { queue<int>q; memset(vis,0,sizeof(vis)); memset(d,INF,sizeof(d)); q.push(source); d[source]=0; cur[source]=-1; int minflow=INF, i; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(d[v]>d[u]+edge[i].cost&&edge[i].cap) { d[v]=d[u]+edge[i].cost; minflow=min(minflow,edge[i].cap); cur[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } if(d[sink]==INF) return 0; flow+=minflow; cost+=minflow*d[sink]; if(flow>=k) { return 0; } for(i=cur[sink]; i!=-1; i=cur[edge[i^1].v]) { edge[i].cap-=minflow; edge[i^1].cap+=minflow; } return 1; } void mcmf() { flow=0; cost=0; while(spfa()); //printf("%d %d\n",flow, cost); if(flow<k) printf("-1\n"); else printf("%d\n",cost); } int main() { int n, m, i, j, u, v, a, c; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { memset(head,-1,sizeof(head)); cnt=0; source=1; sink=n; while(m--) { scanf("%d%d%d%d",&u,&v,&a,&c); for(i=1; i<=c; i++) { //printf("--\n"); add(u,v,1,a*(i*2-1)); } } mcmf(); } return 0; }