01分数规划思维题。
题中要求交通总量不减少,那么如果总量增加的话,总费用就会增加,所以一定不是更优的解。那么总量守恒。
这是不是就想到了网络流?对于每一个节点流入量等于流出量。然后就是很有思维的一个转化了:把压缩看成退流,把扩容看成增广。
边(x, y)一次压缩,就建一条y -> x,容量为a - d的边。
边(x, y)一次增广,就建一条x -> y,容量为b + d的边。也就是一次调整多出来的费用。那么这样建完图后,图中的一个环就代表一种调整方案!
回头看题,让求某一个比值最小,那一定会想到01分数规划,令ans = max((X - Y) / k),那么ans >= (X - Y) / k,于是有ans * k + Y - X >= 0。按上述的建图,Y - X就是环上的边权和,k就是环中的点数(边数),所以这个式子相当于每经过一条边,这条边的边权就加一个ans,那么ans * k + Y - X >= 0就可以写成Σ(ans + ei) >= 0。二分的时候,如果存在负环,说明mid取小了,向右二分;否则向左二分。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 5e3 + 5; 21 const int maxe = 3e3 + 5; 22 inline ll read() 23 { 24 ll ans = 0; 25 char ch = getchar(), last = ' '; 26 while(!isdigit(ch)) {last = ch; ch = getchar();} 27 while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();} 28 if(last == '-') ans = -ans; 29 return ans; 30 } 31 inline void write(ll x) 32 { 33 if(x < 0) x = -x, putchar('-'); 34 if(x >= 10) write(x / 10); 35 putchar(x % 10 + '0'); 36 } 37 38 int n, m; 39 struct Edge 40 { 41 int nxt, to, w; 42 }e[maxe << 1]; 43 int head[maxn], ecnt = -1; 44 void addEdge(int x, int y, int w) 45 { 46 e[++ecnt] = (Edge){head[x], y, w}; 47 head[x] = ecnt; 48 } 49 50 db dis[maxn]; 51 bool vis[maxn], mak[maxn]; 52 bool spfa(int now, db x) 53 { 54 vis[now] = mak[now] = 1; 55 for(int i = head[now]; i != -1; i = e[i].nxt) 56 { 57 if(dis[e[i].to] > dis[now] + e[i].w + x) 58 { 59 dis[e[i].to] = dis[now] + e[i].w + x; 60 if(vis[e[i].to]) return 1; 61 if(spfa(e[i].to, x)) return 1; 62 } 63 } 64 vis[now] = 0; 65 return 0; 66 } 67 68 bool judge(db x) 69 { 70 Mem(vis, 0); Mem(mak, 0); 71 for(int i = 1; i <= n + 2; ++i) 72 if(!mak[i]) 73 { 74 if(spfa(i, x)) return 1; 75 } 76 return 0; 77 } 78 79 int main() 80 { 81 Mem(head, -1); 82 n = read(); m = read(); 83 for(int i = 1; i <= m; ++i) 84 { 85 int x = read(), y = read(), a = read(), b = read(), c = read(), d = read(); 86 if(c) addEdge(y, x, a - d); 87 addEdge(x, y, b + d); 88 } 89 db L = 0, R = 1e5; 90 while(R - L > eps) 91 { 92 db mid = (L + R) / 2.00; 93 if(judge(mid)) L = mid; 94 else R = mid; 95 } 96 printf("%.2lf\n", L); 97 return 0; 98 }