Hdu 3667 Transportation(最小费用流+思路)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3667

思路:平方关系,直接建图每次增广并不是最优。。。。

1^2=1,2^2=1+3,3^2=1+3+5,4^2=1+3+5+7.......

所以,对于每条边<x,y>,若流量为c,则在x与y之间连c条边,流量均为1,费用分别为a[i],3*a[i],5*a[i].........由于每次增广时流量相同时选择最小花费的边,若该边<x,y>流量为c,则总花费为a[x]+3*a[x]+5*a[x]+.........+(2*c-1)*a[x]=a[x]*c^2,符合题意。对新图求最小费用最大流即可,若最大流小于k,则无解。

#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debu
using namespace std;
typedef long long LL;
const int maxn=200;
const int INF=0x3f3f3f3f;
struct Edge
{
    int from,to,cap,flow,cost;
    Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w) {}
};
queue<int> q;
vector<Edge> edges;
vector<int> G[maxn];
int n,m,k,p[maxn],a[maxn];
int inq[maxn],d[maxn];
LL cost;
void init(int n)
{
    memset(p,0,sizeof(p));
    memset(a,0,sizeof(a));
    memset(d,0,sizeof(d));
    for(int i=0; i<=n+1; i++) G[i].clear();
    edges.clear();
}
void addedges(int from,int to,int cap,int cost)
{
    edges.push_back(Edge(from,to,cap,0,cost));
    edges.push_back(Edge(to,from,0,0,-cost));
    int m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
bool BF(int s,int t,int& flow,LL& cost)
{
    while(!q.empty()) q.pop();
    for(int i=0; i<=n; i++) d[i]=INF;
    memset(inq,0,sizeof(inq));
    d[s]=0,inq[s]=1,p[s]=0;
    q.push(s);
    a[s]=INF;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int i=0; i<G[u].size(); i++)
        {
            Edge& e=edges[G[u][i]];
            if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
            {
                d[e.to]=d[u]+e.cost;
                p[e.to]=G[u][i];
                a[e.to]=min(a[u],e.cap-e.flow);
                if(!inq[e.to])
                {
                    q.push(e.to);
                    inq[e.to]=1;
                }
            }
        }
    }
    if(d[t]==INF) return 0;
    flow+=a[t];
    cost+=(LL)d[t]*(LL)(a[t]);
    //cout<<a[t]<<" "<<d[t]<<" "<<flow<<" "<<cost<<endl;
    for(int u=t; u!=s; u=edges[p[u]].from)
    {
        edges[p[u]].flow+=a[t];
        edges[p[u]^1].flow-=a[t];
    }
    return 1;
}
int mincostmaxflow(int s,int t,LL& cost)
{
    int flow=0;
    cost=0;
    while(BF(s,t,flow,cost));
    return flow;
}
int main()
{
#ifdef debug
    freopen("in.in","r",stdin);
#endif // debug
    ios::sync_with_stdio(0);
    while(cin>>n>>m>>k)
    {
        init(n);
        for(int i=0; i<m; i++)
        {
            int x,y,c,w,tmp=1;
            cin>>x>>y>>w>>c;
            //cout<<x<<" "<<y<<" "<<w<<" "<<c<<endl;
            for(int j=1; j<=c; j++)
            {
                addedges(x,y,1,w*tmp);
                tmp+=2;
            }
        }
        addedges(0,1,k,0);
        //cout<<"123"<<endl;
        int tmp=mincostmaxflow(0,n,cost);
        //cout<<tmp<<endl;
        if(tmp<k) cout<<-1<<endl;
        else cout<<cost<<endl;
        //cout<<"flag"<<endl;
    }
    return 0;
}
时间: 2024-12-13 17:11:35

Hdu 3667 Transportation(最小费用流+思路)的相关文章

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

hdu 3667 拆边加最小费用流

Transportation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2301    Accepted Submission(s): 966 Problem Description There are N cities, and M directed roads connecting them. Now you want to t

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 3667

http://acm.hdu.edu.cn/showproblem.php?pid=3667 最小费用最大流 本题流量和费用不是线性关系,fee=a*flow*flow,所以常规套模板spfa无法得到最小费用 观察到每条边流量上限只有5,则可以把一条流量为f的边拆成f条流量为1的边,每条边费用是a*(2*i-1)(1<=i<=f) #include <iostream> #include <cstring> #include <cstdio> #includ

hdu 3667(最小费用最大流+拆边)

Transportation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2670    Accepted Submission(s): 1157 Problem Description There are N cities, and M directed roads connecting them. Now you want to

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

题意: 在一般费用流题目改动:路过某路,每x单位流量须要花费 ai*x^2(ai为给定的系数). 開始的的时候,一看仅仅只是是最后统计费用上在改动罢了,一看例子.发现根本没那么简单(ps:以后每次写程序前先看例子能不能过.),由于是成平方关系.每次一流量增广的话.下次未必最优!于是想到我每次仅仅增长一个单位流量.每次增长一个单位之后,该路径上的全部边的费用边改为i^2-(i-1)^2,(第一次肯定增广a,其次的话3a.5a.7a....由于第一次已经增广了,和为第i次i平方就可以! )如此.符合

hdu 4790 Just Random (思路+分类计算+数学)

Problem Description Coach Pang and Uncle Yang both love numbers. Every morning they play a game with number together. In each game the following will be done: 1. Coach Pang randomly choose a integer x in [a, b] with equal probability. 2. Uncle Yang r

hdu 5701 中位数计数 思路题

中位数计数 Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 909    Accepted Submission(s): 346 Problem Description 中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数. 现在有n个数,每个数都是独一无二的,求出每个数在多少个包

HDU 3667 费用流(拆边)

题意:有n个城市(1~n),m条有向边:有k件货物要从1运到n,每条边最多能运c件货物,每条边有一个危险系数ai,经过这条路的费用需要ai*x2(x为货物的数量),问所有货物安全到达的费用. 思路:c<=5,这里可以做文章:把每条边拆成c条边,容量都为1,费用为ai*(2*i-1)(第二个i是指拆边时的第几条边).推导:x2-(x-1)2=2x-1. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #define min(x,y)