题意:给出两种关于防御站位置的信息,一种是确切的信息,P A B X,表示a在b北面x距离的地方,另一种是V A B,表示只知道A在B的北面。问这些信息有没有矛盾。
分析:差分约束。第一种记为A-B>=X && A-B<=X,第二种记为A-B>=0,用SPFA求得解,则没有矛盾,否则就有矛盾。
#include <iostream> #include <stdio.h> #include <queue> using namespace std; const int N=1001; const int E=2*100000+1000; const int inf=10000000; struct edge{ int to,w,next; }; int adj[N]; edge e[E];//存放顶点的所有邻接边 bool visit[N]; int d[N]; /*记录节点更新的次数,如果超过n次,说明存在回路 由于约束图中含有n+1个顶点,所以每个顶点被松弛的次数不能能超过n */ int cnt[N]; int edge_num=0,n=0,m=0; bool spfa() { int s,u,v,i,w; s=0; queue<int> q; for(i=0;i<=n;i++) visit[i]=false; for(i=0;i<=n;i++) cnt[i]=0; visit[s]=true; q.push(s); //将源点加入到队列中 while(!q.empty()) { u=q.front(); // cout<<"出队:"<<u<<endl; q.pop(); visit[u]=false; //遍历u的所有邻接边 for(i=adj[u];i!=-1;i=e[i].next) { v=e[i].to; w=e[i].w; // cout<<"v"<<v<<endl; if(d[u]+w < d[v]) { d[v]=d[u]+w; if(!visit[v]) { visit[v]=true; q.push(v); cnt[v]++; if(cnt[v]>n) //更新不超过n,有n+1个顶点,一开始写成>=n了 { // delete []visit; return false; } } } } } return true; } int main() { char ch; int i,u,v,w; while(scanf("%d%d",&n,&m)!=EOF) { edge_num=0; for(i=0;i<=n;i++) { adj[i]=-1; d[i]=inf; } d[0]=0; for(i=0;i<m;i++) { cin>>ch; if(ch == 'P') { scanf("%d%d%d",&u,&v,&w); e[edge_num].to=u; e[edge_num].w=w; e[edge_num].next=adj[v]; adj[v]=edge_num++; e[edge_num].to=v; e[edge_num].w=(-1)*w; e[edge_num].next=adj[u]; adj[u]=edge_num++; } else { //x1-x2>=1,转化为约束条件为x2-x1<=-1 scanf("%d%d",&u,&v); e[edge_num].to=v; e[edge_num].w=-1; e[edge_num].next=adj[u]; adj[u]=edge_num++; } } //添加源点到其他顶点的边,权值为0 for(i=1;i<=n;i++) { e[edge_num].to=i; e[edge_num].w=0; e[edge_num].next=adj[0]; adj[0]=edge_num++; } if(!spfa()) printf("Unreliable\n"); else printf("Reliable\n"); } return 0; }