第一行包含二個整數N,Mphp
一個浮點數,保留二位小數。表示答案,數據保證答案大於0c++
1<=N<=5000網絡
很容易就能夠想到01分數規劃,而後思考怎麼判斷是否有可行解
一次完整的修改應該是找兩條路徑,一條路徑容量擴大1,流量擴大1,另外一條流量-1,容量縮小1
若是第一條路徑上的邊爲e1,第二條路徑上的邊爲e2,代價就是 $\sum{a_{e1}}+\sum{d_{e1}}-\sum{d_{e2}}+\sum{b_{e2}}$spa
能夠發現這兩條路徑除掉前面的公共路徑以後能夠造成一個無向環,而且一條邊的擴容、縮容付出的代價是獨立的
獲得一個思路:創建雙向邊,正向邊權是擴容代價,若是容量上限不爲0,反向邊權是縮容代價,不然不建反向邊code
因爲題目的答案分式和變化的容量無直接關係,因此容量變化1和變化x是沒有區別的,直接檢查容量變化1是否可行
01規劃判斷的時候,把每一個環的權值定義爲 $邊數*mid+\sum邊權$
把每條邊權值加上mid後找負環,若是存在負環就有可行解,不然沒有blog
1 #include<bits/stdc++.h> 2 #define N 5010 3 using namespace std; 4 const double eps=1e-3; 5 int n,m,tot,fg,hd[N],vis[N];double d[N]; 6 struct edge{int v,w,next;}e[N<<1]; 7 void adde(int u,int v,int w){ 8 e[++tot].v=v; 9 e[tot].next=hd[u]; 10 e[tot].w=w; 11 hd[u]=tot; 12 } 13 void dfs(int u,double x){ 14 vis[u]=1; 15 if(fg)return; 16 for(int i=hd[u];i;i=e[i].next){ 17 int v=e[i].v; 18 if(d[v]>d[u]+x+e[i].w){ 19 d[v]=d[u]+x+e[i].w; 20 if(vis[v]){fg=1;return;} 21 dfs(v,x); 22 } 23 } 24 vis[u]=0; 25 } 26 bool check(double x){ 27 fg=0;memset(d,0,sizeof(d)); 28 memset(vis,0,sizeof(vis)); 29 for(int i=1;i<=n&&!fg;i++)dfs(i,x); 30 return fg; 31 } 32 int main(){ 33 scanf("%d%d",&n,&m); 34 n+=2;int u,v,a,b,c,d; 35 for(int i=1;i<=m;i++){ 36 scanf("%d%d%d%d%d%d",&u,&v,&a,&b,&c,&d); 37 adde(u,v,b+d);if(c)adde(v,u,a-d); 38 } 39 double l=0,r=1e6,mid,ans; 40 while(l+eps<=r){ 41 mid=(l+r)/2; 42 if(check(mid))l=ans=mid; 43 else r=mid; 44 } 45 printf("%.2lf\n",ans); 46 return 0; 47 }