[BZOJ2330][SCOI2011]糖果 差分约束系统+最短路
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2330
类似于题目中这种含有不等式关系,我们可以建立差分约束系统来跑最长路或最短路。
对于一个不等式$X_1-X_2>=a$我们可以看成是$X_1>=X_2+a$,把$X_1$和$X_2$看成两个点,我们可以发现这个关系跟最长路中的$dis[v]>=dis[u]+w[i]$很像,就是最长路中的点一定满足这样的关系。
所以我们就按着这个思路,先把关于点$X_1$,$X_2$和边$a$的图建好,再来跑一遍最长路,如果有解,就一定满足题目中的不等式关系。
具体连边方式就是若有$a>=b+c$,则连$b$到$a$,边权为$c$。最短路同理。
最长路无解的情况就是存在正权环,最短路存在负权环。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 typedef long long ll; 7 const int INF=1<<30; 8 int inline readint(){ 9 int Num;char ch; 10 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 11 while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0'; 12 return Num; 13 } 14 int N,K; 15 int to[300010],ne[300010],w[300010],fir[100010],cnt=0; 16 void Add(int a,int b,int c){ 17 to[++cnt]=b; 18 w[cnt]=c; 19 ne[cnt]=fir[a]; 20 fir[a]=cnt; 21 } 22 int vis[100010],dis[100010]; 23 bool in[100010]; 24 queue <int> q; 25 ll spfa(){ 26 for(int i=1;i<=N;i++) dis[i]=-INF; 27 in[N+1]=true; 28 q.push(N+1); 29 dis[N+1]=0; 30 vis[N+1]=1; 31 int u; 32 while(!q.empty()){ 33 u=q.front(); 34 q.pop(); 35 in[u]=false; 36 for(int i=fir[u];i!=-1;i=ne[i]){ 37 int v=to[i]; 38 if(dis[v]<dis[u]+w[i]){ 39 dis[v]=dis[u]+w[i]; 40 if(!in[v]){ 41 q.push(v); 42 in[v]=true; 43 vis[v]++; 44 if(vis[v]>N) return -1; 45 } 46 } 47 } 48 } 49 ll ans=0; 50 for(int i=1;i<=N;i++) ans+=dis[i]; 51 return ans; 52 } 53 int main(){ 54 memset(fir,-1,sizeof(fir)); 55 N=readint(); 56 K=readint(); 57 for(int i=1;i<=K;i++){ 58 int X=readint(), 59 A=readint(), 60 B=readint(); 61 switch(X){ 62 case 1: 63 Add(B,A,0); 64 Add(A,B,0); 65 break; 66 case 2: 67 if(A==B){ 68 puts("-1"); 69 return 0; 70 } 71 Add(A,B,1); 72 break; 73 case 3: 74 Add(B,A,0); 75 break; 76 case 4: 77 if(A==B){ 78 puts("-1"); 79 return 0; 80 } 81 Add(B,A,1); 82 break; 83 case 5: 84 Add(A,B,0); 85 break; 86 } 87 } 88 for(int i=N;i>=1;i--) Add(N+1,i,1); 89 printf("%lld\n",spfa()); 90 return 0; 91 }