题目大意:一天南北线上有n个防御站,给出他们之间的位置关系,问有没有可能存在这样一种位置布置符合所给的位置关系。关系有两种,一种是 P A B X,表示A在B北边X光年的位置,V A B表示A在B北边至少1光年位置。
分析:仍然考虑差分约束,容易想到,若关系为P,则
s[a]-a[b]=c;
变换一下则变成:
s[b]-s[a]<=-c;
s[a]-a[b]<=c;
若关系为V,则
s[b]-s[a]<=-1;
这样转换之后就变成了求最短路了,注意这道题可能无解,无解即表现为存在负环,判断方法为:如果一个点入队超过n次,则该图存在负环,直接退出。
细节方面的话,注意读入要使用字符串读入,要使用超级源并且超级源到各点距离为0,多组数据的初始化以及存在负环的话需要在从队首取出元素后立即将此元素标记为未入队(因为有可能出现x->y权值为1,y->x权值为-2等情况)。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #define mem(a) memset(a,0,sizeof(a)) #define mem1(a) memset(a,127,sizeof(a)) const int maxn=1e5+5; using namespace std; struct point{ int next,w,to; }e[maxn*3]; int tot,first[maxn],maxx=0,q[maxn]; int dis[maxn],sum[maxn]; bool vis[maxn]; int n,m,a,b,c; char ch[2]; int read() { int ans=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} return ans*f; } void add(int u,int v,int wi) { tot++;e[tot].next=first[u];first[u]=tot;e[tot].to=v;e[tot].w=wi; } void init() { tot=0;mem(first);mem1(dis);mem(vis);mem(sum); for(int i=1;i<=n;i++)add(0,i,0); } bool spfa() { int head=0,tail=1; q[head]=0;vis[0]=1;dis[0]=0; while(head!=tail){ int x=q[head];head++;if(head>=100000)head=0; vis[x]=0; for(int i=first[x];i;i=e[i].next){ int to=e[i].to; if(dis[to]>dis[x]+e[i].w){ dis[to]=dis[x]+e[i].w; if(!vis[to]){ sum[to]++; vis[to]=1; q[tail]=to;tail++; if(tail>=100000)tail=0; if(sum[to]>n)return 0; } } } } return 1; } int main() { while(scanf("%d %d",&n,&m)==2){ init(); for(int i=1;i<=m;i++){ scanf("%s",ch);a=read();b=read(); if(ch[0]=='P'){ c=read(); add(a,b,-c);add(b,a,c); } else add(a,b,-1); } if(spfa())printf("Reliable "); else printf("Unreliable "); } return 0; }