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;
}
时间: 2024-11-20 18:05:12

hdu 3667 /2010哈尔滨赛区H题 费用与流量为非线性关系/费用流的相关文章

zoj 3662 第37届ACM/ICPC长春赛区H题(DP)

题目:给出K个数,使得这K个数的和为N,LCM为M,问有多少种 f[i][j][k]表示选i个数,总和为j,最小公倍数为k memery卡的比较紧,注意不要开太大,按照题目数据开 这种类型的dp也是第一次做 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue&g

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

2014 HDU多校弟八场H题 【找规律把】

看了解题报告,发现看不懂 QAQ 比较简单的解释是这样的: 可以先暴力下达标,然后会发现当前数 和 上一个数 的差值是一个 固定值, 而且等于当前数与i(第i个数)的商, 于是没有规律的部分暴力解决,有规律的套公式 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <cstring&g

HDU - 4813 Hard Code (长春赛区水题)

Description Some strange code is sent to Da Shan High School. It's said to be the prophet's note. The note is extremely hard to understand. However, Professor Meng is so smart that he successfully found the pattern of the code. That is, the length of

HDU - 4814 Golden Radio Base (长春赛区B题)

最小二乘法又叫做最小平方法,是一种数学优化技术.它通过最小化误差的平方和寻找数据的最佳函数匹配. 通常情况下最小二乘法用于求回归问题.以简单的线性最小二乘为例,二维平面上给定个点的坐标,确定一条直线, 要求大致符合这个点的走向. 我们可以设这条直线的方程为,那么就要使在处的函数值与给定的值相 差达到最小,也就是说,要确定的值,使得 最小.根据这种方法求的值就是典型的最小二乘法. 可以看出是的一个二元函数,要求的最小值,那么求偏导,有 进一步得到 然后联立两式可以解出,如果方程数比较多,我们可以用

hdu2448 / 费用流 / harbin赛区c题

题(自)目(己)错(英)综(语)复(太)杂(差),关系理了半小时+翻译才看明白,看明白之后,直接建图,费用流击杀./简单题. 2A:有的地方,可用互通的要建双向边! #include<cstdio> #include<iostream> #include<queue> #include<cstring> #include<string> using namespace std; const int maxv=400; const int maxe

HDU 3667 费用流 拆边 Transportation

题意: 有N个城市,M条有向道路,要从1号城市运送K个货物到N号城市. 每条有向道路<u, v>运送费用和运送量的平方成正比,系数为ai 而且每条路最多运送Ci个货物,求最小费用. 分析: 拆边,每条边拆成费用为a, 3a, 5a的边,这样就能保证每条边的费用和流量的平方成正比. 因为最多运送K个货物,所以增加一个源点和城市1连一条容量为K费用为0的边. 跑一边最小费用最大流,如果满流才有解. 1 #include <iostream> 2 #include <cstdio&

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

hdu 1999 不可摸数 水题。

不可摸数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7966    Accepted Submission(s): 2024 Problem Description s(n)是正整数n的真因子之和,即小于n且整除n的因子和.例如s(12)=1+2+3+4+6=16.如果任何数m,s(m)都不等于n,则称n为不可摸数. Input 包