题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667
思路:由于花费的计算方法是a*x*x,因此必须拆边,使得最小费用流模板可用,即变成a*x的形式。具体的拆边方法为:第i次取这条路时费用为(2*i-1)*a (i<=5),每条边的容量为1。如果这条边通过的流量为x,那正好sigma(2*i-1)(1<<i<<x)==x^2。然后就是跑最小费用最大流了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 222
#define MAXM 22222222
#define inf 1<<30 struct Edge{
int v,cap,cost,next;
}edge[MAXM]; int n,m,k,NE;
int head[MAXN]; void Insert(int u,int v,int cap,int cost)
{
edge[NE].v=v;
edge[NE].cap=cap;
edge[NE].cost=cost;
edge[NE].next=head[u];
head[u]=NE++; edge[NE].v=u;
edge[NE].cap=;
edge[NE].cost=-cost;
edge[NE].next=head[v];
head[v]=NE++;
} int dist[MAXN];
bool mark[MAXN];
int cur[MAXN],pre[MAXN];
bool spfa(int vs,int vt)
{
memset(mark,false,sizeof(mark));
fill(dist,dist+n+,inf);
dist[vs]=;
queue<int>que;
que.push(vs);
while(!que.empty()){
int u=que.front();
que.pop();
mark[u]=false;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v,cost=edge[i].cost;
if(edge[i].cap>&&dist[u]+cost<dist[v]){
dist[v]=dist[u]+cost;
pre[v]=u;
cur[v]=i;
if(!mark[v]){
mark[v]=true;
que.push(v);
}
}
}
}
return dist[vt]<inf;
} int MinCostFlow(int vs,int vt)
{
int cost=,flow=;
while(spfa(vs,vt)){
int aug=inf;
for(int u=vt;u!=vs;u=pre[u]){
aug=min(aug,edge[cur[u]].cap);
}
flow+=aug;cost+=dist[vt]*aug;
for(int u=vt;u!=vs;u=pre[u]){
edge[cur[u]].cap-=aug;
edge[cur[u]^].cap+=aug;
}
}
if(flow<k)cost=-;
return cost;
} int main()
{
int u,v,cost,cap;
while(~scanf("%d%d%d",&n,&m,&k)){
NE=;
memset(head,-,sizeof(head));
while(m--){
scanf("%d%d%d%d",&u,&v,&cost,&cap);
for(int i=;i<=cap;i++){
Insert(u,v,,(*i-)*cost);
}
}
Insert(,,k,);
printf("%d\n",MinCostFlow(,n));
}
return ;
}