大致题意:
告诉你有一列长度为n的数列和m个关系式。每个关系式的表述为:
si ni “gt” c 或者是 si ni “lt” c。分别代表该数列第si项一直加到第si+ni项的和大于c,和第si项一直加到第si+ni项的和小于c。求是否存在满足以上m个要求的数列。是则输出“lamentable kingdom”,否则输出“successful conspiracy”。
大致思路:
把问题转化为差分约束。将差分约束系统中的点sum[i]设为这个数列前i项的和。当要求第si项一直加到第si+ni项的和大于c的时候,就等价于sum[si+ni]-sum[si-1]>c,又由于差分约束系统中只能出现<=关系且这里的数字都是整数,所以上式又可以转化为sum[i-1]-sum[i+n]<=-c-1。
对于“第si项一直加到第si+n项的和小于c”的要求,我们同样可以将其转化为sum[si+ni]-sum[si-1]<=c-1;
按照得到的式子构出差分约束系统,用spfa判断是否存在可行解即可。
详细代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> using namespace std; const int nMax=1050; const int mMax=1000050; const int inf=1<<28; struct{ int v, next; int w; }edge[mMax]; int n, k, head[nMax]; int dis[nMax],issea[nMax]; int stack[nMax],m,sum[nMax]; bool vis[nMax]; void addedge(int a,int b,int w){ edge[k].w = w; edge[k].v=b; edge[k].next=head[a]; head[a]=k;k++; } bool spfa(int s){ int i, top = 0; memset(vis,0,sizeof(vis)); for(i=0;i<=n;i++)dis[i]=inf; dis[s]=0; stack[++top]=s; vis[s]=true; while(top){ // cout<<top<<endl; int u=stack[top--]; for(i=head[u];i!=0;i=edge[i].next){ int v=edge[i].v; if(dis[v]>dis[u]+edge[i].w){ dis[v]=dis[u]+edge[i].w; if(!vis[v]){ vis[v]=true; stack[++top] = v; if(++sum[v]>n)return 0; // cout<<v<<" "<<sum[v]<<endl;; } } } vis[u]=false; } return 1; } int main(){ int i,j,si,ni,c,s; char str[10]; while(scanf("%d",&n)!=EOF&&n){ scanf("%d",&m); k=1; s=n+2; //s作为加入差分约束系统的“虚拟点” memset(head,0,sizeof(head)); memset(sum,0,sizeof(sum)); for(i=1;i<=n;i++){ addedge(s,i,0); } while(m--){ scanf("%d%d%s%d",&si,&ni,str,&c); if(str[0]=='g'){ addedge(si+ni,si-1,-c-1); } else{ addedge(si-1,si+ni,c-1); } } if(spfa(s)){ printf("lamentable kingdom\n"); } else{ printf("successful conspiracy\n"); } } return 0; }