标签:style blog color strong for io
【题意】:
给出一张有向图(信息为点数,边数,每条边的起点终点和权值),然后可以让你做任意次如下操作:
选择任意节点v和一个数值d,使以v为终点的边的权值减d,以v为起点的边的权值加d,
最后要满足两个条件:这些边的权值为非负,这些边中权值最小的边的权值尽量大。
【知识点】:
Bellman-Ford+差分约束系统
【题解】:
差分约束系统:是判断不等式组有解的一种方法(具体原理还不甚理解,以后还会具体补充该文章)
例如有若干不等式形如xj-xi<=ak 那么以i为起点j为终点ak为权值建图,然后用Bellman-Ford跑,若能求出最短路,则说明不等式有解,否则则不。
因为操作次序不影响最终结果,故设sum(a)为在点a上进行操作的值的和,那么可以知道操作完毕后边a->b的值为w(a,b)+sum(a)-sum(b)。
然后再设经过一系列操作后这些边中权值最小的边为x,则对任意边满足x<=w(a,b)+sum(a)-sum(b),变形得sum(b)-sum(a)<=w(a,b)-x。
首先判断(未进行操作前最大边的值)+1是否可以作为权值最小的边,若可行则说明每条边的值可以通过操作无限增大。
判断1,若不可行则说明不管怎么进行操作都不能保证所有边都为非负。然后二分权值最小的边。
判断可行即通过查分约束系统。
【代码】:
摘自刘汝佳 训练指南
1 // UVa11478 Halum 2 // Rujia Liu 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 8 const int INF = 1000000000; 9 const int maxn = 500 + 10; 10 const int maxm = 2700 + 10; 11 12 struct Edge { 13 int to, dist; 14 }; 15 16 // 邻接表写法 17 struct BellmanFord { 18 int n, m; 19 Edge edges[maxm]; 20 int head[maxn]; 21 int next[maxm]; 22 bool inq[maxn]; // 是否在队列中 23 int d[maxn]; // s到各个点的距离 24 int cnt[maxn]; // 进队次数 25 26 void init(int n) { 27 this->n = n; 28 m = 0; 29 memset(head, -1, sizeof(head)); 30 } 31 32 void AddEdge(int from, int to, int dist) { 33 next[m] = head[from]; 34 head[from] = m; 35 edges[m++] = (Edge){to, dist}; 36 } 37 38 bool negativeCycle() { 39 queue<int> Q; 40 memset(inq, 0, sizeof(inq)); 41 memset(cnt, 0, sizeof(cnt)); 42 for(int i = 0; i < n; i++) { d[i] = 0; Q.push(i); } 43 44 int u; 45 while(!Q.empty()) { 46 u = Q.front(); Q.pop(); 47 inq[u] = false; 48 for(int i = head[u]; i != -1; i = next[i]) { 49 Edge& e = edges[i]; 50 if(d[e.to] > d[u] + e.dist) { 51 d[e.to] = d[u] + e.dist; 52 if(!inq[e.to]) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to] > n) return true; } 53 } 54 } 55 } 56 return false; 57 } 58 }; 59 60 BellmanFord solver; 61 62 // 判断在初始差分约束系统的每个不等式右侧同时减去x之后是否有解 63 bool test(int x) { 64 for(int i = 0; i < solver.m; i++) 65 solver.edges[i].dist -= x; 66 bool ret = solver.negativeCycle(); 67 for(int i = 0; i < solver.m; i++) 68 solver.edges[i].dist += x; 69 return !ret; // 如果有负环,说明差分约束系统无解 70 } 71 72 int main() { 73 int n, m; 74 while(scanf("%d%d", &n, &m) == 2) { 75 solver.init(n); 76 int ub = 0; 77 while(m--) { 78 int u, v, d; 79 scanf("%d%d%d", &u, &v, &d); ub = max(ub, d); 80 solver.AddEdge(u-1, v-1, d); 81 } 82 83 if(test(ub+1)) printf("Infinite\n"); // 如果可以让每条边权都>ub,说明每条边的权都增加了,重复一次会增加得更多...直到无限 84 else if(!test(1)) printf("No Solution\n"); 85 else { 86 int L = 2, R = ub, ans = 1; 87 while(L <= R) { 88 int M = L + (R-L)/2; 89 if(test(M)) { ans = M; L = M+1; } else R = M-1; 90 } 91 printf("%d\n", ans); 92 } 93 } 94 return 0; 95 }
UVA 11478 Bellman-Ford+差分约束系统,布布扣,bubuko.com
标签:style blog color strong for io
原文地址:http://www.cnblogs.com/Ntcrush/p/3832094.html