题意: 在一般费用流题目改动:路过某路,每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;
}

最新文章

  1. Eclipse不自动编译java文件的终极解决方案
  2. thinkphp模板引擎
  3. POJ 2785 4 Values whose Sum is 0
  4. android 小米手机连接到电脑adb无法识别 解决方案
  5. 查找IP来源
  6. ubuntu 配置jdk
  7. secureCRT端口转发功能
  8. HDU2036 改革春风吹满地
  9. toolbar ,textfield,图片拉伸,Bundle
  10. mysql与nagios的结合使用
  11. FB面经 Prepare: Make Parentheses valid
  12. day46-python爬虫学习
  13. ant 安装 网址
  14. 平面图转对偶图&amp;19_03_21校内训练 [Everfeel]
  15. 查看电脑的IP地址及配置
  16. doubleclick video notes
  17. S老师 Shader 学习
  18. Java程序流程控制:判断结构、选择结构、循环结构
  19. Python sys.md
  20. 【Spark】SparkStreaming-Tasks-数量如何设置?

热门文章

  1. 百度之星初赛(A)——T1
  2. Asp .Net MVC中常用过滤属性类
  3. [LeetCode]Word Search 回溯
  4. Linux Context , Interrupts 和 Context Switching 说明【转】
  5. 配置wpa_supplicant调试wifi linux下命令行连接wifi
  6. l2tp连接不上,修复
  7. C#中axWindowsMediaPlayer控件的用法
  8. Python的并发并行[4] -&gt; 并发[1] -&gt; concurrent.future 模块
  9. Python的程序结构[3] -&gt; 变量/Variable[1] -&gt; LEGB 法则
  10. 【BZOJ2276】Temperature