BZOJ3130: [Sdoi2013]費用流
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 11 2 10
2 3 15
Sample Output
1010.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]費用流