题目链接:UVa 515 King
差分约束系统。
如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如xj-xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。
求解差分约束系统,可以转化成图论的单源最短路径(或最长路径)问题。
观察xj-xi<=bk,会发现它类似最短路中的三角不等式d[v]<=d[u]+w[u,v],即d[v]-d[u]<=w[u,v]。因此,以每个变量xi为结点,对于约束条件xj-xi<=bk,连接一条边(i,j),边权为bk。我们再增加一个源点s,s与所有定点相连,边权均为0。对这个图,以s为源点运行Bellman-ford算法(或SPFA算法),最终{d[ i]}即为一组可行解。(来自百度百科)
本题利用前n个元素的和作为节点,即设s[i] = a[1] + a[2] + …a[i]。
有a[si] + a[si+1] + … + a[si + ni] = s[si + ni] - s[si - 1],所以如果a[si] + a[si+1] + … + a[si + ni] < k 则 s[si + ni] - s[si - 1] < k <= k - 1;如果a[si] + a[si+1] + … + a[si + ni] > k 则 s[si - 1] - s[si + ni] < -k <= -k - 1;
需要注意的地方时这个题本身是存在0这个点的(我刚开始把0作为添加的源点果断错了),因为需要表示s[1]。
增加的源点作为第n + 1个点,那么总共是有n + 2个点的,所以用SPFA判断存在负环应该是一个点进入队列的次数大于等于n + 2。
#include <iostream> #include <cstring> #include <stdio.h> #include <queue> using namespace std; const int MAX_N = 200 + 10; int head[MAX_N],d[MAX_N],cnt[MAX_N],vis[MAX_N]; const int INF = (1 << 30); struct Edge { int v, w, next; }; Edge edge[MAX_N]; int n, m, _count; void addEdge(int u, int v, int w) { edge[_count].v = v; edge[_count].w = w; edge[_count].next = head[u]; head[u] = _count++; } bool SPFA() { memset(vis,0,sizeof(vis)); memset(cnt,0,sizeof(cnt)); for(int i = 0;i <= n;i++) d[i] = INF; d[n + 1] = 0; queue<int> Q; Q.push(n + 1); cnt[n + 1]++; while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int e = head[u]; e != -1; e = edge[e].next) { if(d[edge[e].v] > d[u] + edge[e].w) { d[edge[e].v] = d[u] + edge[e].w; if(!vis[edge[e].v]) { Q.push(edge[e].v); vis[edge[e].v] = true; cnt[edge[e].v]++; if(cnt[edge[e].v] >= n + 2)// 0 ~ n + 1 共有n + 2个点 return false; } } } } return true; } int main() { while(scanf("%d", &n), n) { scanf("%d", &m); int s, len, k; char str[10]; _count = 0; memset(head, -1, sizeof(head)); for(int i = 0; i <= n; i++) addEdge(n + 1, i, 0);//添加从n + 1 到所有点的路径,设置边权为0 for(int i = 1; i <= m; i++) { scanf("%d%d%s%d", &s, &len, str, &k); if(str[0] == 'g')//将大于转换为小于等于 addEdge(s + len, s - 1, -k - 1); else//将小于转化为小于等于 addEdge(s - 1, s + len, k - 1); } if(!SPFA()) printf("successful conspiracy\n"); else printf("lamentable kingdom\n"); } return 0; }