题目描述
题解
由于是连续的序列,想到转化成前缀和相减的形式。
由于约束值都是整数,所以小于/大于一个数可以转化为小于等于/大于等于这个数减1或加1;
这样我们就十分巧妙地把它转换成了差分约束系统的基本模型。
那么剩下的就是spfa了。
注意此题可能有好几个连通块,所以要加超级源。并且spfa要判断负环。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int max_n=105;
const int max_m=105;
const int max_M=max_m*10;
const int max_e=max_M*2;
char s[5];
int n,m,st,cnt,w,u,t;
int tot,next[max_e],point[max_n],v[max_e],c[max_e];
int dis[max_n],insert[max_n];
bool vis[max_n];
queue <int> q;
inline void clear(){
tot=0;
memset(next,0,sizeof(next));
memset(point,0,sizeof(point));
memset(v,0,sizeof(v));
memset(c,0,sizeof(c));
memset(insert,0,sizeof(insert));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
}
inline void addedge(int x,int y,int z){
++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
}
inline bool spfa(){
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[n+1]=0;
vis[n+1]=true;
while (!q.empty()) q.pop();
q.push(n+1);
insert[n+1]++;
while (!q.empty()){
int now=q.front(); q.pop();
vis[now]=false;
for (int i=point[now];i;i=next[i])
if (dis[v[i]]>dis[now]+c[i]){
dis[v[i]]=dis[now]+c[i];
if (!vis[v[i]]){
vis[v[i]]=false;
q.push(v[i]);
insert[v[i]]++;
if (insert[v[i]]>n+3) return false;
}
}
}
return true;
}
int main(){
while (~scanf("%d%d",&n,&m)){
if (!n) break;
clear();
for (int i=1;i<=m;++i){
scanf("%d%d",&st,&cnt);
scanf("%s",s);
scanf("%d",&w);
if (s[0]=='g'){
w++;
w=-w;
u=st+cnt;
t=st-1;
addedge(u,t,w);
}
else{
w--;
u=st-1;
t=st+cnt;
addedge(u,t,w);
}
}
for (int i=0;i<=n;++i)
addedge(n+1,i,0);
bool pd=spfa();
if (pd) printf("lamentable kingdom\n");
else printf("successful conspiracy\n");
}
}
总结
①添加超级源之后spfa一定是从超级源开始跑。
②spfa判断负环的条件是某一个点入队超过n次。(可以稍微大一点)