【链接】
poj1364
【题目大意】
给你n和m,以及m个约束条件,对于每个约束条件给出si,ni,oi,ki,求是否有一个n个元素的序列a能满足这些约束条件。其中oi可以分别表示为gt(>)和lt(<),约束条件的定义为
asi+asi+1+⋯+asi+ni>ki
或
asi+asi+1+⋯+asi+ni<ki
。
【解题报告】
了解题目大意后,就可以想到这题是差分约束。但是从题目表面上却很难实现代码。进一步思考可以发现对于
asi
~
asi+ni
的加和,我们可以用前缀和求出,定义以
sum[x]
表示
a1
~
ax
的加和,所以
asi
~
asi+ni
的加和就是
sum[si+ni]−sum[si−1]
。对于>和<的转换推导如下:
sum[si+ni]−sum[si−1]<ki
->
sum[si+ni]−sum[si−1]<=ki−1
sum[si+ni]−sum[si−1]>ki
->
sum[si−1]−sum[si+ni]<=−ki−1
有了以上的推导,spfa判环就出解了。
Ps:因为存在图不完全连通的情况,所以可以加个超级源解决此类情况。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105,maxm=205;
int n,m,st,tot,num[maxn],dst[maxn],que[maxn],lnk[maxn],son[maxm],nxt[maxm],w[maxm];
bool vis[maxn];
inline int Read()
{
int res=0,f=1;
char ch=getchar(),cc=ch;
while (ch<'0'||ch>'9') cc=ch,ch=getchar();
if (cc=='-') f=-1;
while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=getchar();
return res*f;
}
void Add(int x,int y,int z)
{
w[++tot]=z; son[tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
bool Spfa()
{
memset(dst,63,sizeof(dst));
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
dst[st]=0; vis[st]=1; que[1]=st;
int hed=0,til=1;
while (hed!=til)
{
hed=(hed+1)%maxn;
int x=que[hed]; vis[x]=0;
for (int j=lnk[x]; ~j; j=nxt[j])
if (dst[x]+w[j]<dst[son[j]])
{
dst[son[j]]=dst[x]+w[j];
if (!vis[son[j]])
{
vis[son[j]]=1; til=(til+1)%maxn; que[til]=son[j]; num[son[j]]++;
if (num[son[j]]>n+1) return 0;
if (dst[que[(hed+1)%maxn]]>dst[que[til]]) swap(que[(hed+1)%maxn],que[til]);
}
}
}
return 1;
}
void Work()
{
m=Read(); tot=0; st=n+1;
memset(lnk,255,sizeof(lnk));
for (int i=1; i<=m; i++)
{
int x=Read(),y=x+Read(); x--;
char ch=getchar();
while (ch!='g'&&ch!='l') ch=getchar();
int z=Read();
if (ch=='l') Add(x,y,z-1); else Add(y,x,-z-1);
}
for (int i=0; i<=n; i++) Add(st,i,0);
if (Spfa()) printf("lamentable kingdom"); else printf("successful conspiracy"); putchar(10);
n=Read();
}
int main()
{
freopen("1364.in","r",stdin);
freopen("1364.out","w",stdout);
n=Read();
while (n) Work();
return 0;
}