题意:给出n个变量,m个约束公式 asi + asi+1 + .... + asi+ni < ki or > ki ,叫你判断是否存在着解满足这m组约束公式。
题解:对于 asi + asi+1 + ....... + asi + n < ki or > ki,因为ai和ki都为整,设sum[n] 为 变量ai的前n个和,则可以转化为 sum[si+n] - sum[si-1] <= ki -1 or sum[si-1] - sum[si+n] <= -1-ki ,这样问题就转化为差分约束的情况。体会了差分约束系统的两个性质。第一就是处理的只能是>=或者<=。第二就是差分约束系统的解可以平移。开始做这题的时候就没注意到题中是>和<。另外就是Spfa判断负权回路时需要入队次数>=顶点数。
PS:差分约束根本不需要什么附加顶点, 附加顶点的唯一用处就是保证图的连通性, 不让你有负环判不到的情况, 解决这种问题的最佳途径就是初始把所有顶点都加入队列, 并且将所有dis置0, 这就相当于加了一个不存在的附加顶点, 它与所有的顶点的直连长度都是0. 但是注意在判负环时必须是"cnt>n"而不是"cnt>=n", 因为第一次所有顶点入队只是相当于把一个附加顶点加入到队列中而已, 不应该算在cnt中, 如果在此步骤没有增加过cnt, 则">="也是可以的。
#include <iostream> using namespace std; #define N 150 #define INF 9999999 int n, m, size; bool mark[N]; int head[N], dis[N]; int que[N], inque[N]; struct Edge { int v, w, next; }; Edge edge[N]; bool Spfa() { memset(mark,0,sizeof(mark)); memset(inque,0,sizeof(inque)); for ( int i = 0; i <= n+1; i++ ) dis[i] = INF; int u, v, front, rear; front = rear = 0; mark[n+1] = true; inque[n+1]++; dis[n+1] = 0; que[rear] = n+1; rear = ( rear + 1 ) % N; while ( front != rear ) { u = que[front]; front = ( front + 1 ) % N; mark[u] = false; for ( int i = head[u]; i; i = edge[i].next ) { v = edge[i].v; if ( dis[v] > dis[u] + edge[i].w ) { dis[v] = dis[u] + edge[i].w; if ( ! mark[v] ) { que[rear] = v; rear = ( rear + 1 ) % N; mark[v] = true; inque[v]++; if ( inque[v] >= n+2 ) return false; } } } } return true; } void add ( int u, int v, int w ) { size++; edge[size].v = v; edge[size].w = w; edge[size].next = head[u]; head[u] = size; } int main() { char oper[5]; int a, b, c; while ( scanf("%d",&n) && n ) { scanf("%d",&m); size = 0; memset(head,0,sizeof(head)); while ( m-- ) { scanf("%d %d %s %d",&a,&b,&oper,&c); if ( oper[0] == 'g' ) add ( a+b, a-1, -(c+1) ); else add ( a-1, a+b, c-1 ); } for ( int i = 0; i <= n; i++ ) add ( n+1, i, 0 ); if ( Spfa() ) printf("lamentable kingdom\n"); else printf("successful conspiracy\n"); } return 0; }