1. 程式人生 > >BZOJ3130: [Sdoi2013]費用流

BZOJ3130: [Sdoi2013]費用流

多少 費用流 con pos fin script 題解 include -s

Description

Alice和Bob在圖論課程上學習了最大流和最小費用最大流的相關知識。
最大流問題:給定一張有向圖表示運輸網絡,一個源點S和一個匯點T,每條邊都有最大流量。一個合法的網絡流方案必須滿足:(1)每條邊的實際流量都不超過其最大流量且非負;(2)除了源點S和匯點T之外,對於其余所有點,都滿足該點總流入流量等於該點總流出流量;而S點的凈流出流量等於T點的凈流入流量,這個值也即該網絡流方案的總運輸量。最大流問題就是對於給定的運輸網絡,求總運輸量最大的網絡流方案。


上圖表示了一個最大流問題。對於每條邊,右邊的數代表該邊的最大流量,左邊的數代表在最優解中,該邊的實際流量。需要註意到,一個最大流問題的解可能不是唯一的。 對於一張給定的運輸網絡,Alice先確定一個最大流,如果有多種解,Alice可以任選一種;之後Bob在每條邊上分配單位花費(單位花費必須是非負實數),要求所有邊的單位花費之和等於P。總費用等於每一條邊的實際流量乘以該邊的單位花費。需要註意到,Bob在分配單位花費之前,已經知道Alice所給出的最大流方案。現茌Alice希望總費用盡量小,而Bob希望總費用盡量大。我們想知道,如果兩個人都執行最優策略,最大流的值和總費用分別為多少。

Input

第一行三個整數N,M,P。N表示給定運輸網絡中節點的數量,M表示有向邊的數量,P的含義見問題描述部分。為了簡化問題,我們假設源點S是點1,匯點T是點N。
接下來M行,每行三個整數A,B,C,表示有一條從點A到點B的有向邊,其最大流量是C。

Output

第一行一個整數,表示最大流的值。
第二行一個實數,表示總費用。建議選手輸出四位以上小數。

Sample Input

3 2 1
1 2 10
2 3 15

Sample Output

10
10.0000

HINT

【樣例說明】

對於Alice,最大流的方案是固定的。兩條邊的實際流量都為10。


對於Bob,給第一條邊分配0.5的費用,第二條邊分配0.5的費用。總費用

為:10*0.5+10*0.5=10。可以證明不存在總費用更大的分配方案。

【數據規模和約定】

對於20%的測試數據:所有有向邊的最大流量都是1。

對於100%的測試數據:N < = 100,M < = 1000。

對於l00%的測試數據:所有點的編號在I..N範圍內。1 < = 每條邊的最大流

量 < = 50000。1 < = P < = 10。給定運輸網絡中不會有起點和終點相同的邊。

題目傳送門 這道題貌似掛了??網上的題解都過不了,先寫博客吧 首先最大流一遍求第一問,然後想第二問。。 這tm不還是最大流嗎?? 你二分一個流量上限,然後在findflow裏面min一下就可以了 代碼如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m;
double p;
const double eps=1e-8;
double INF=1e16;
struct node{
    int x,y,next,other;
    double c;
}a[21000],e[21000];int len,last[21000];
void ins(int x,int y,double c)
{
    int k1,k2;
    k1=++len;
    e[len].x=x;e[len].y=y;e[len].c=c;
    e[len].next=last[x];last[x]=len;
    
    k2=++len;
    e[len].x=y;e[len].y=x;e[len].c=0;
    e[len].next=last[y];last[y]=len;
    
    e[k1].other=k2;
    e[k2].other=k1;
}
int list[110000],h[110000];
int st,ed,head,tail;
bool bt_h()
{
    memset(h,0,sizeof(h));h[st]=1;
    list[1]=st;head=1,tail=2;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(h[y]==0&&a[k].c>0)
            {
                h[y]=h[x]+1;
                list[tail++]=y;
            }
        }
        head++;
    }
    if(h[ed]>0)return true;
    return false;
}
double findflow(int x,double f)
{
    if(x==ed)return f;
    double s=0,t;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(h[y]==h[x]+1&&a[k].c>0.0&&s<f)
        {
            s+=(t=findflow(y,min(a[k].c,f-s)));
            a[k].c-=t;a[a[k].other].c+=t;        
        }
    }
    if(s==0.0)h[x]=0;
    return s;
}
double ans;
bool check(double C)
{
    memcpy(a,e,sizeof(a));
    for(int i=1;i<=len;i++)a[i].c=min(a[i].c,C);
    double sum=0.0;
    while(bt_h()==true)
        sum+=findflow(st,INF);
    if(sum-ans>=-eps)return true;
    return false;
}
int main()
{
    double r=0.0;
    scanf("%d%d%lf",&n,&m,&p);st=1,ed=n;
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=m;i++)
    {
        double cc;int x,y;
        scanf("%d%d%lf",&x,&y,&cc);
        ins(x,y,cc);r=max(r,cc);
    }
    memcpy(a,e,sizeof(a));
    ans=0.0;
    while(bt_h()==true)
        ans+=findflow(st,INF);
    printf("%.0lf\n",ans);
    double l=0.0;double sum=r;
    while(l<=r)
    {
        double mid=(l+r)/2;
        if(check(mid)==true){sum=mid,r=mid-eps;}
        else l=mid+eps;
    }
    printf("%.7lf\n",sum*p);
    return 0;
}

by_lmy

BZOJ3130: [Sdoi2013]費用流