题意:
给出n个点的m条约束信息。每条信息表述为(P a b c)表示a在b北方距离c的位置,或者(V a b) 表示a在b北方1单位距离或者更远的位置。问是否可能存在符合以上m个要求的点。
解题思路:
差分约束一般给我的印象都是一个范围性的式子才能写出不等式,但是这道题,固定的距离可以用两个只有不等式号相反的式子表示,这样子可以将值限定在“=”的那个值上。
把dis[i]设为其到始点的距离。第二个条件很简单dis[a]-dis[b]>=1 也就是dis[b]<=dis[a]-1。对于第一个,带等于号的条件dis[a]-dis[b]==c,我们可以转化为dis[a]-dis[b]>=c和dis[a]-dis[b]<=c 两个不等式,然后再转化为最短路三角不等式。由于可能出现多个不连通图的情况,所以要设一个虚拟始点,与所有点相连,长度设为0。然后用spfa来判定是否有可行解。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-8 #define inf 1e9 using namespace std; const int nMax=200050; const int mMax=1000050; struct{ int u,v,nxt; int w; }e[mMax]; int n,cnt,head[nMax]; int dis[nMax]; int que[nMax],m,sum[nMax]; bool vis[nMax]; void add(int u,int v,int w){ e[cnt].w=w; e[cnt].u=u; e[cnt].v=v; e[cnt].nxt=head[u]; head[u]=cnt; cnt++; } bool spfa(int s){ int i,hhead=0,tail=1; for (i=0;i<=n;i++){ dis[i]=inf; vis[i]=0; } dis[s]=0; vis[s]=1; que[0]=s; while (hhead!=tail){ int u=que[hhead]; vis[u]=0; for (int p=head[u];p!=0;p=e[p].nxt){ int v=e[p].v; if (dis[v]>dis[u]+e[p].w){ dis[v]=dis[u]+e[p].w; if (!vis[v]){ vis[v]=1; que[tail++]=v; if (tail==nMax) tail=0; if (++sum[v]>n) return 0; } } } hhead++; if (hhead==nMax) hhead=0; } return 1; } int main(){ int m,a,b,c,s; char str[20]; while (cin>>n>>m){ s=0; cnt=1; memset(sum,0,sizeof(sum)); memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); while (m--){ scanf("%s",str); if (str[0]=='P'){ scanf("%d%d%d",&a,&b,&c); add(b,a,c); add(a,b,-c); } else { scanf("%d%d",&a,&b); add(a,b,-1); } } for (int i=1;i<=n;i++){ add(s,i,0); } if (spfa(s)) printf("Reliable\n"); else printf("Unreliable\n"); } return 0; }