Time Limit: 3000MS | Memory Limit: 131072K | |
Total Submissions: 11106 | Accepted: 3481 |
Description
The galaxy war between the Empire Draco and the Commonwealth of Zibu broke out 3 years ago. Draco established a line of defense called Grot. Grot is a straight line with N defense stations. Because of the cooperation of the stations, Zibu’s Marine Glory cannot march any further but stay outside the line.
A mystery Information Group X benefits form selling information to both sides of the war. Today you the administrator of Zibu’s Intelligence Department got a piece of information about Grot’s defense stations’ arrangement from Information Group X. Your task is to determine whether the information is reliable.
The information consists of M tips. Each tip is either precise or vague.
Precise tip is in the form of P A B X
, means defense station A is X light-years north of defense station B.
Vague tip is in the form of V A B
, means defense station A is in the north of defense station B, at least 1 light-year, but the precise distance is unknown.
Input
There are several test cases in the input. Each test case starts with two integers N (0 < N ≤ 1000) and M (1 ≤ M ≤ 100000).The next M line each describe a tip, either in precise form or vague form.
Output
Output one line for each test case in the input. Output “Reliable” if It is possible to arrange N defense stations satisfying all the M tips, otherwise output “Unreliable”.
Sample Input
3 4 P 1 2 1 P 2 3 1 V 1 3 P 1 3 1 5 5 V 1 2 V 2 3 V 3 4 V 4 5 V 3 5
Sample Output
Unreliable Reliable
题目大意:
给出m个信息,判断这些信息是否可靠。
解题思路:
差分约束+优化的Bellman算法。
dis[i]表示超级源点到i点的距离;
建立<=的差分约束;
由于P A B X 指“确定A到B的距离(边权)为X”
从P A B X得到的差分系统为
dist[A] - dist[B] >= X && dist[A] - dist[B] <= X
等价于 dist[B] <= dist[A] - X && dist[A] <= dist[B] + X
则if(dist[B] > dist[A]-X) 松弛:dist[B] = dist[A]-X
由于 V A B指“只知道A到B的距离(边权)至少为1”
从V A B得到的差分系统为 dist[A] >= dist[B] +1
等价于 dist[B] <= dist[A] -1 则if(dist[B] > dist[A] -1) 松弛:dist[B] = dist[A] -1
代码如下:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> using namespace std; #define inf 999999 struct node { int s,e; } edge[2000000]; int dis[1001]; //源点到各点的距离 int w[200001]; //边权 int main() { int i,j; int n; //太空站数目 int m; //tips数 while(scanf("%d %d",&n,&m)!=EOF) { memset(dis,0,sizeof(dis)); //初始化源点到各点的距离 int pe=0; for(i=0; i<m; i++) { char ch; int a,b,x; getchar(); //吃掉回车 scanf("%c",&ch); if(ch=='P') //清晰边权,即A、B间距离确定,建立双向边 { scanf("%d %d %d",&a,&b,&x); edge[pe].s=a; edge[pe].e=b; w[pe++]=x; edge[pe].s=b; edge[pe].e=a; w[pe++]=-x; } else if(ch=='V') //模糊边权,即A、B间距离不确定,建立单向边 { scanf("%d %d",&a,&b); edge[pe].s=a; edge[pe].e=b; w[pe++]=1; } } //Bellman-Ford bool sign; //用于Bellman-Ford算法优化 for(i=0; i<n; i++) { sign=false; for(j=0; j<pe; j++) if(dis[ edge[j].e ] > dis[ edge[j].s ] - w[j]) { dis[ edge[j].e ] = dis[ edge[j].s ] - w[j]; sign=true; } if(!sign)//若dist没有任何改变,则以后也不会改变,可以直接退出循环 break; }//循环n次后若flag == false 说明有负权回路,或者权值矛盾 if(sign) cout<<"Unreliable"<<endl; //存在负权环 else cout<<"Reliable"<<endl; //不存在负权环 } return 0; }
方法二: SPFA
思路:
差分约束还是很神奇。
我的理解,本质是在对N个点排序,这么多点之间有距离关系,因为存在V这种模糊距离关系,所以距离关系有约束。
顾用差分约束系统来解决。
主要差分方程:
1.i-j>=w && i-j<=w (j-i>=-w);
2.i-j>=1;
spfa松弛方程
if(d[v]<d[u]+w)
d[v]=d[u]+w;
即d[i]始终保存节点i的取值范围的左边界。
然后则是检查负环,如果某个节点入队列次数>n,则有负环。(由bellman-ford得知边的松弛次数最大只需N-1).
代码如下:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define Abs(a) ((a)>0?(a):(-(a))) #define llong long long int using namespace std; const int N=1005,M=100005; const int inf=999999; int n,m; struct Edge { int v,w,next; } edge[3*M]; int edgehead[N]; int _n; int que[N*N]; int d[N]; bool vis[N]; int times[N]; void addedge(int u ,int v,int w) { edge[_n].v=v; edge[_n].w=w; edge[_n].next=edgehead[u]; edgehead[u]=_n++; } bool spfa(int s) { bool ans=true; memset(vis,0,sizeof(vis)); memset(times,0,sizeof(times)); int head=1,tail=1; que[tail++]=s; times[s]=1; vis[s]=true; while(head<tail&&ans) { int now=que[head++]; vis[now]=false; for(int i=edgehead[now]; i; i=edge[i].next) { int v=edge[i].v; int w=edge[i].w; if(d[v]<d[now]+w) { d[v]=d[now]+w; if(!vis[v]) { if(times[v]>n) { ans=false; break; } vis[v]=true; que[tail++]=v; times[v]++; } } } } return ans; } void solve() { int s=n+1; for(int i=1; i<=n; i++) addedge(s,i,1); if(spfa(s)) printf("Reliable\n"); else printf("Unreliable\n"); } int main() { while(scanf("%d %d",&n,&m)!=EOF) { _n=1; memset(d,0,sizeof(d)); memset(edge,0,sizeof(edge)); memset(edgehead,0,sizeof(edgehead)); char cha; int u,v; for(int i=1; i<=m; i++) { scanf(" %c",&cha); scanf("%d %d",&u,&v); if(cha=='P') { int w; scanf("%d",&w); addedge(u,v,w); addedge(v,u,-w); } else { addedge(u,v,1); } } solve(); } return 0; }