对于一个刚接触差分约束系统的OIer来说,这算是一道细节比较多,也比较难的题。首先就是这道题有5种不同的约束条件,对于条件1,3,5直接按照差分条件建边即可,条件2,4要先移项,再建边。之后再求单源最长路,好不容易做出来后你就会发现数据卡SPFA!!!!这里可以加两个小小的优化:1)当a,b严格大于或小于时,他们不能为同一个人,先预判出来可以节省大量时间(不加#5会TLE)。还有要倒序建边,,,(没有任何道理,倒序就能AC,正序会TLE)
参考程序如下:
1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 #include<cstdio> 5 using namespace std; 6 long long n,m,dist[350005],v[350005],w[350005],nxt[350005],head[350005],cnt,x,a,b,ring[350005]; 7 bool vis[350005]; 8 inline int read() 9 { 10 int f=1,x=0; 11 char s=getchar(); 12 while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} 13 while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} 14 return x*f; 15 } 16 inline void add(int a,int b,int c) 17 { 18 v[++cnt]=b; 19 w[cnt]=c; 20 nxt[cnt]=head[a]; 21 head[a]=cnt; 22 } 23 inline bool spfa(int node) 24 { 25 queue<int>q; 26 q.push(node); 27 vis[node]=1; 28 while(!q.empty()) 29 { 30 int c=q.front(); 31 q.pop(); 32 vis[c]=0; 33 ring[c]++; 34 //cout<<c<<endl; 35 if(ring[c]==n)return 0; 36 for(int i=head[c];i;i=nxt[i]) 37 { 38 int y=v[i]; 39 //cout<<"-------------------CJXGBH---------------------"<<endl; 40 //cout<<dist[y]<<" "<<dist[c]<<" "<<w[i]<<endl; 41 if(dist[y]<dist[c]+w[i]) 42 { 43 dist[y]=dist[c]+w[i]; 44 if(!vis[y]) 45 { 46 q.push(y); 47 vis[y]=1; 48 } 49 } 50 } 51 } 52 return 1; 53 } 54 int main() 55 { 56 //freopen("1.in","r",stdin); 57 n=read();m=read(); 58 for(int i=1;i<=m;i++) 59 { 60 x=read();a=read();b=read(); 61 if(x==1) 62 { 63 add(a,b,0); 64 add(b,a,0); 65 } 66 if(x==2) 67 { 68 add(a,b,1); 69 if(a==b) 70 { 71 cout<<"-1"; 72 return 0; 73 } 74 } 75 if(x==3) 76 { 77 add(b,a,0); 78 } 79 if(x==4) 80 { 81 add(b,a,1); 82 if(a==b) 83 { 84 cout<<"-1"; 85 return 0; 86 } 87 } 88 if(x==5) 89 { 90 add(a,b,0); 91 } 92 } 93 for(int i=n;i>=1;i--) 94 { 95 add(0,i,1); 96 } 97 if(!spfa(0)) 98 { 99 cout<<"-1"; 100 return 0; 101 } 102 long long ans=0; 103 for(int i=1;i<=n;i++)ans+=dist[i]; 104 cout<<ans; 105 return 0; 106 }