[SCOI2011]糖果
题目大意:
有n个正整数,k个约束条件。条件分为5种:
1.a和b相等;
2.a小于b;
3.a不小于b;
4.a大于b;
5.a不大于b。
问条件是否矛盾,如果不矛盾,求它们最小和。
思路:
差分约束。
把数当作点,约束关系当作边,跑SPFA,如果有环则说明矛盾。
1 #include<queue> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 typedef long long int64; 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=100001; 14 struct Edge { 15 int to,w; 16 }; 17 std::vector<Edge> e[N]; 18 inline void add_edge(const int &u,const int &v,const int &w) { 19 e[u].push_back((Edge){v,w}); 20 } 21 bool inq[N]; 22 std::queue<int> q; 23 int dis[N],cnt[N],n; 24 bool spfa() { 25 q.push(0); 26 inq[0]=true; 27 while(!q.empty()) { 28 const int x=q.front(); 29 q.pop(); 30 inq[x]=false; 31 if(++cnt[x]>=n) return false; 32 for(register unsigned i=0;i<e[x].size();i++) { 33 const int &y=e[x][i].to,&w=e[x][i].w; 34 if(dis[x]+w>dis[y]) { 35 dis[y]=dis[x]+w; 36 if(!inq[y]) { 37 q.push(y); 38 inq[y]=true; 39 } 40 } 41 } 42 } 43 return true; 44 } 45 int main() { 46 n=getint(); 47 for(register int k=getint();k;k--) { 48 int t=getint(),a=getint(),b=getint(); 49 if(t==1) { 50 add_edge(a,b,0); 51 add_edge(b,a,0); 52 } 53 if(t==2) { 54 if(a==b) { 55 puts("-1"); 56 return 0; 57 } 58 add_edge(a,b,1); 59 } 60 if(t==3) add_edge(b,a,0); 61 if(t==4) { 62 if(a==b) { 63 puts("-1"); 64 return 0; 65 } 66 add_edge(b,a,1); 67 } 68 if(t==5) add_edge(a,b,0); 69 } 70 for(register int i=1;i<=n;i++) { 71 add_edge(0,i,1); 72 } 73 if(!spfa()) { 74 puts("-1"); 75 return 0; 76 } 77 int64 ans=0; 78 for(register int i=1;i<=n;i++) ans+=dis[i]; 79 printf("%lld\n",ans); 80 return 0; 81 }