首页 > 代码库 > hdu 3667 /2010哈尔滨赛区H题 费用与流量为非线性关系/费用流
hdu 3667 /2010哈尔滨赛区H题 费用与流量为非线性关系/费用流
题意: 在一般费用流题目修改:路过某路,每x单位流量需要花费 ai*x^2(ai为给定的系数)。
开始的的时候,一看只不过是最后统计费用上在修改罢了,一看样例,发现根本没那么简单(ps:以后每次敲代码前先看样例能不能过!),因为是成平方关系,每次一流量增广的话,下次未必最优!于是想到我每次只增长一个单位流量!每次增长一个单位之后,该路径上的所有边的费用边改为i^2-(i-1)^2,(第一次肯定增广a,其次的话3a.5a.7a.。。。由于第一次已经增广了,和为第i次i平方即可!)如此,符合题意!一提交Wa!扫了一遍代码,发现反向边的费用没有改!于是修改:想到反向边的本质是提供后悔机会,而我控制的是每次增长一个单位!后悔一次的话,必然是付上一次的费用!所以,与平时不同:初始化反向边费用也为W(不是-W),每次增广修改为-1a.-3a.-5a,这样控制比正向边慢一步!(其实这才是反向边的本质作用,只是平时时候费用是不变的,所以无需如此!)提交后AC!(ps:感觉对费用流算法内部逻辑更加清晰了有木有)
后来看了网上的题解:看数据流量为<5,所以每条边拆为流量为1的,每条费用也如此递增。其次,这样本质是还是每次增广流量1,可谓异曲同工。不过拆边的思想值得借鉴!
额外收获:1:注意看数据范围,有时候可以从上面思考算法。2:敲代码前先过一遍样例,或许有思路启发!
#include<cstdio> #include<iostream> #include<queue> #include<cstring> using namespace std; const int maxv=200; const int maxe=5000*2*2; const int inf=0x3f3f3f3f; int nume=0;int e[maxe][5];int head[maxv]; int n,m,k; void inline adde(int i,int j,int c,int w,int f) //新添加一个参数f,记录初始费用。费用w改变 { e[nume][0]=j;e[nume][1]=head[i];head[i]=nume; e[nume][2]=c;e[nume][3]=w;e[nume++][4]=f; e[nume][0]=i;e[nume][1]=head[j];head[j]=nume; e[nume][2]=0;e[nume][3]=w;e[nume++][4]=f; } int inq[maxv];int pre[maxv];int prv[maxv]; int d[maxv]; bool spfa(int &sum,int &flow) { int s=0,t=n+1; for(int i=0;i<=n+3;i++) { inq[i]=0; d[i]=inf; } queue<int>q; q.push(s); inq[s]=1; d[s]=0; while(!q.empty()) { int cur=q.front(); q.pop(); inq[cur]=0; for(int i=head[cur];i!=-1;i=e[i][1]) { int v=e[i][0]; if(e[i][2]>0&&d[cur]+e[i][3]<d[v]) { d[v]=d[cur]+e[i][3]; pre[v]=i; prv[v]=cur; if(!inq[v]) { q.push(v); inq[v]=1; } } } } if(d[t]==inf)return 0; int cur=t; int minf=1; //每次增广一个单位 while(cur!=s) { int fe=pre[cur]; e[fe][3]+=e[fe][4]*2; //关键点。 e[fe^1][3]-=e[fe][4]*2; //比正向边慢一步更新。(初始值来控制) cur=prv[cur]; } cur=t; while(cur!=s) { e[pre[cur]][2]-=minf; e[pre[cur]^1][2]+=minf; cur=prv[cur]; } flow+=minf; sum+=d[t]; //,每次一单位,不用说,最短路即为总费用 return 1; } int mincost(int &flow) { int sum=0; while(spfa(sum,flow)); return sum; } void init() { nume=0; for(int i=0;i<=n+2;i++) head[i]=-1; } int main() { while(~scanf("%d%d%d",&n,&m,&k)) { init(); int a,b,x,c; for(int j=0;j<m;j++) { scanf("%d%d%d%d",&a,&b,&x,&c); adde(a,b,c,x,x); } adde(0,1,k,0,0); adde(n,n+1,k,0,0); //附加边来判断流量满否,方便 int flow=0; int ans=mincost(flow); if(flow!=k) printf("-1\n"); else printf("%d\n",ans); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。