zoukankan      html  css  js  c++  java
  • 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
    ");
            else printf("%d
    ",ans);
        }
        return 0;
    }
    



  • 相关阅读:
    《中断学习(一) —— Linux中断流程以及处理机制》
    《C语言知识点 —— 字符串指针和字符串数组的区别》
    《驱动实例 —— 触发外部中断后通过异步通知机制发送信号给用户态》
    《驱动学习 —— 杂项设备》
    玩转----adb adb monkey命令及介绍
    玩转----黑盒技术设计测试用例的方法主要有
    玩转----LoadRunner具体流程
    玩转----软件立项阶段
    玩转----Linux之ant安装部署
    玩转----Ubuntu 16.04安装JDK并配置环境变量
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925701.html
Copyright © 2011-2022 走看看