题意:给定一个有向图,从1号结点运送K单位的物品到N号结点,每条边有一个参数a,如果经过这条边运送x单位的物品,则费用为a*x*x,求最小费用。
常见的费用流是费用*流量,这里流量变成了平方,所以直接套用最小费用流是行不通的。由于题目中每条边的最大流量最多为5,所以可以考虑把边拆开多条流量为1的边,然后费用叠加上去,即费用依次为1*a,3*a,5*a,7*a,9*a,这样叠加起来刚好是对应的平方的值。
然后就可以直接跑费用流的算法了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N = 110;
const int INF = 0x7fffffff;
#define pb push_back
struct Edge{
int from,to,cap,flow,cost;
};
vector<Edge> G;
vector<int> V[N];
int n, m, s, t, K, a[N], p[N], d[N];
bool inq[N];
void init(){
t = n+1;
G.clear();
for(int i=0; i<=t; i++) V[i].clear();
}
void add(int from, int to, int cap, int cost){
G.pb((Edge){from,to,cap,0,cost});
G.pb((Edge){to,from,0,0,-cost});
int x = G.size();
V[from].pb(x-2);
V[to].pb(x-1);
}
bool BellmanFord(int &flow, int &cost){
memset(inq,0,sizeof(inq));
for(int i=0; i<=t; i++) d[i]=INF;
d[0]=0; inq[0]=1; a[0]=INF; p[0]=-1;
queue<int> Q;
Q.push(0);
while(!Q.empty()){
int x=Q.front(); Q.pop();
inq[x]=0;
for(int i=0; i<V[x].size(); i++){
int j= V[x][i];
Edge &e = G[j];
if(e.cap>e.flow && d[e.to]>d[x]+e.cost){
d[e.to] = d[x]+e.cost;
p[e.to] = j;
a[e.to] = min(a[x], e.cap-e.flow);
if(!inq[e.to]){
Q.push(e.to);
inq[e.to]=1;
}
}
}
}
if(d[t]==INF) return 0;
int x = t;
flow += a[t];
cost += d[t]*a[t];
while(x){
G[p[x]].flow += a[t];
G[p[x]^1].flow -= a[t];
x = G[p[x]].from;
}
return 1;
}
int MinCost(int &cost){
cost=0;
int flow=0;
while(BellmanFord(flow,cost));
return flow==K;
}
int fee[5]={1,3,5,7,9};
int main(){
while(~scanf("%d %d %d", &n, &m, &K)){
init();
int a, b, c, d;
while(m--){
scanf("%d %d %d %d", &a, &b, &c, &d);
for(int i=0; i<d; i++){
add(a, b, 1, fee[i]*c);
}
}
add(0, 1, K, 0);
add(n, t, K, 0);
int cost;
if(MinCost(cost)) printf("%d\n", cost);
else puts("-1");
}
return 0;
}