差分约束系统的第一个题目,看了落花大神的博客后,对差分约束有了一定了解,关键在于建图,然后就是判断是否存在负权回路。
关于差分约束系统的解释详见维基百科:http://zh.wikipedia.org/wiki/%E5%B7%AE%E5%88%86%E7%BA%A6%E6%9D%9F%E7%B3%BB%E7%BB%9F
利用spfa判断时,当图中有顶点出队次数多于图中顶点数目时说明存在负环。
其实我自己敲上去的时候改了一点点。
大神的time[g[x][i].v]当达到n+1时就返回false,这是不对的,因为点包括0嘛,所以最终应该有n+1个点,判断就应该改为达到n+2,而且这一点也从uva上得到证明,
直接交n+1的版本是过不了的,n+2,才能过。
以下是我改过大神的代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <cstdlib> 5 #include <vector> 6 #define N 110 7 using namespace std; 8 9 struct edgeType{ 10 int v, w; 11 edgeType(int a, int b):v(a), w(b){} 12 }; 13 int n, m, d[N], time[N], inq[N]; 14 char op[10]; 15 16 vector<edgeType> g[N]; 17 bool spfa(void) 18 { 19 queue<int> q; 20 time[n] = 1; 21 inq[n] = 1; 22 q.push(n); 23 while(!q.empty()) 24 { 25 int x = q.front(); 26 q.pop(); 27 inq[x] = 0; 28 for(int i = 0; i < g[x].size(); i++) 29 if(d[g[x][i].v] > d[x] + g[x][i].w) 30 { 31 d[g[x][i].v] = d[x] + g[x][i].w; 32 time[g[x][i].v]++; 33 if(time[g[x][i].v] == n+2) 34 return false; 35 if(!inq[g[x][i].v]) 36 { 37 q.push(g[x][i].v); 38 inq[g[x][i].v] = 1; 39 } 40 } 41 } 42 return true; 43 } 44 45 int main(void) 46 { 47 int a, b, c; 48 while(scanf("%d%d",&n, &m)&&n) 49 { 50 n++; 51 memset(d, 0x0f, sizeof(d)); 52 memset(inq, 0, sizeof(inq)); 53 memset(time, 0, sizeof(time)); 54 d[n] = 0; 55 g[n].clear(); 56 for(int i = 0; i < n;i++) 57 g[n].push_back(edgeType(i, 0)), g[i].clear(); 58 for(int i = 0; i < m; i++) 59 { 60 scanf("%d%d%s%d", &a, &b, op, &c); 61 if(op[0] == 'g') 62 g[a + b].push_back(edgeType(a - 1, -c - 1)); 63 else g[a - 1].push_back(edgeType(a + b, c - 1)); 64 } 65 if(spfa()) 66 puts("lamentable kingdom"); 67 else puts("successful conspiracy"); 68 } 69 return 0; 70 }
然后我利用bellman—ford重新写了一遍,速度慢了将近一半,不知道是不是我写的姿势不对。
来自维基百科的bellman-ford的伪代码:
# initialization for each v in V do d[v] ← ∞; d[source] ← 0 # Relaxation for i =1,...,|V|-1 do for each edge (u,v) in E do d[v] ← min{d[v], d[u]+w(u,v)} # Negative cycle checking for each edge (u, v) in E do if d[v]> d[u] + w(u,v) then no solution
其实就是普通bellman-ford做完之后,再检查所有的边一次,看看能不能继续松弛,如果可以的话,松弛变数会超过:|V|-1,说明必须存在负权环。
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <cstdlib> 5 #include <vector> 6 #define N 110 7 using namespace std; 8 9 struct edgeType 10 { 11 int v, w; 12 edgeType(int a, int b):v(a), w(b) {} 13 }; 14 int n, m, d[N], inq[N]; 15 char op[10]; 16 vector<edgeType> g[N]; 17 18 bool bellman_ford(void) 19 { 20 for(int k = 0; k < n; k++) 21 for(int x = 0; x <= n; x++) 22 for(int i = 0; i < (int)g[x].size(); i++) 23 if(d[g[x][i].v] > d[x] + g[x][i].w) 24 d[g[x][i].v] = d[x] + g[x][i].w; 25 for(int i = 0; i <= n; i++) 26 { 27 for(int k = 0; k < (int)g[i].size(); k++) 28 if(d[g[i][k].v] > d[i] + g[i][k].w) 29 return false; 30 } 31 return true; 32 } 33 34 int main(void) 35 { 36 int a, b, c; 37 while(scanf("%d",&n)&&n) 38 { 39 n++; 40 scanf("%d", &m); 41 memset(d, 0x0f, sizeof(d)); 42 memset(inq, 0, sizeof(inq)); 43 d[n] = 0; 44 g[n].clear(); 45 for(int i = 0; i < n; i++) 46 g[n].push_back(edgeType(i, 0)), g[i].clear(); 47 for(int i = 0; i < m; i++) 48 { 49 scanf("%d%d%s%d", &a, &b, op, &c); 50 if(op[0] == 'g') 51 g[a + b].push_back(edgeType(a - 1, -c - 1)); 52 else g[a - 1].push_back(edgeType(a + b, c - 1)); 53 } 54 if(bellman_ford()) 55 puts("lamentable kingdom"); 56 else puts("successful conspiracy"); 57 } 58 return 0; 59 }