BZOJ2330 SCOI2010 糖果 最短路
题意:给定N个变量和K个约束条件,形如x1==x2,x1-x2≥a……,求$\sum\limits_{i = 1}^N {{x_i}}$的最小值
题解:
首先差分约束系统是指形如:x[i]-x[j]<d[k]的形式的几个方程联立得到的方程组,其中d均为已知量,x均为未知量。(至于等于好嘛……d--不就好了)
移项之后得到x[i]<d[k]+x[j],这样我们在i和j之间连一条边权为d[k]的边,表示从x[i]得到x[j]必须加d[k](因为这类问题基本上都是要最小化每一个x的值,你既然加上d就满足条件了了,为何要加d+1呢?)。
然后从0(虚点)向所有点连一条长度为w的边(w的值由题目决定——比如说每个x都必须是正数那就连1),然后跑一边最长路,这样每个点的最长路的路径长度就是其在差分约束系统中满足条件的最小值了。(因为所有的条件都要得到满足所以一定是跑最长路)
所以说白了这玩意就是个最短路算法的应用,谁能告诉我这玩意在实际生活中有啥应用……
————————————————————————————————————————————————————————————————————————————
有关本题,必须要从N到1向0连边否则有一个点会T掉,谁能告诉我这逗逼的一点是谁发现的和其原理……
#include <queue> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXN=100000+2; struct HASH{ int u,w; HASH *next; HASH(){} HASH(int _u,int _w,HASH *_next):u(_u),w(_w),next(_next){} }*table[MAXN],mem[MAXN*3]; int N,K,cnt,t[MAXN]; ll d[MAXN],ans; bool flag[MAXN]; queue<int> q; void Insert(int u,int v,int w){ table[u]=&(mem[cnt++]=HASH(v,w,table[u]));} bool SPFA(){ q.push(0),flag[0]=1,t[0]++; while(!q.empty()){ int x=q.front();q.pop(); for(HASH *p=table[x];p;p=p->next) if(d[p->u]<d[x]+p->w){ d[p->u]=d[x]+p->w; if(++t[p->u]>=N) return 0; if(!flag[p->u]) q.push(p->u),flag[p->u]=1; } flag[x]=0; } return 1; } int main(){ scanf("%d %d",&N,&K); for(int i=1,x,a,b;i<=K;i++){ scanf("%d %d %d",&x,&a,&b); if(x%2==0 && a==b){ cout << -1 << endl; return 0; } if(x==1) Insert(a,b,0),Insert(b,a,0); if(x==2) Insert(a,b,1); if(x==3) Insert(b,a,0); if(x==4) Insert(b,a,1); if(x==5) Insert(a,b,0); } for(int i=N;i;i--) Insert(0,i,1); if(!SPFA()) cout << -1 << endl; else{ for(int i=1;i<=N;i++) ans+=d[i]; cout << ans << endl; } return 0; }