题意:给n点,m条边,对于每条边为有向边,给容量和ai,那么这条边的费用就是:实际容量的平方乘以ai,问从1到n运送k单位物资的最小费用。
想法:费用不是线性,所以有的容量不必跑满,甚至是量这条路的最小容量也不用跑满,就像第三个数据,那么就要拆边,拆成容量为一的边,那么剩下的问题就是费用如何给的问题了,因为n^2=1+3+5+7+...+(2*n-1),所以分别给每条容量为一的边赋等式右边的费用就好了,建边是source向1连一条容量为k费用为0的边,n到sink连一条容量为inf费用为0的边。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define inf 0x7fffffff using namespace std; const int nodes=100+50; const int edges=155000; struct node { int u,v,flow,fee; int next; }e[edges]; int n,m,k,s,t; int head[nodes],cnt; class Dinic { public: int spfa() { memset(vis,0,sizeof(vis)); memset(pe,-1,sizeof(pe)); for(int i=s;i<=t;i++) dis[i]=inf; queue<int>q; while(!q.empty()) q.pop(); dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]>dis[u]+e[i].fee&&e[i].flow>0) { dis[v]=dis[u]+e[i].fee; pe[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=inf; } int result() { int res=0; int f=0; while(spfa()) { int minflow=inf; for(int i=pe[t];i+1;i=pe[e[i].u]) { if(minflow>e[i].flow) minflow=e[i].flow; } for(int i=pe[t];i+1;i=pe[e[i].u]) { e[i].flow-=minflow; e[i^1].flow+=minflow; } f+=minflow; res+=dis[t]*minflow; } if(f!=k) return -1; return res; } private: int dis[nodes],pe[nodes],vis[nodes]; }dinic; void Init() { memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b,int flow,int fee) { e[cnt].u=a; e[cnt].v=b; e[cnt].flow=flow; e[cnt].fee=fee; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].u=b; e[cnt].v=a; e[cnt].flow=0; e[cnt].fee=-fee; e[cnt].next=head[b]; head[b]=cnt++; } int main() { while(~scanf("%d%d%d",&n,&m,&k)) { Init(); s=0;t=n+1; add(s,1,k,0); add(n,t,inf,0); for(int i=1;i<=m;i++) { int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d); for(int j=1;j<=d;j++) { add(a,b,1,c*(2*j-1)); } } int res=dinic.result(); printf("%d\n",res); } return 0; }