首页 > 代码库 > UVA 11478 Bellman-Ford+差分约束系统
UVA 11478 Bellman-Ford+差分约束系统
【题意】:
给出一张有向图(信息为点数,边数,每条边的起点终点和权值),然后可以让你做任意次如下操作:
选择任意节点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 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。