poj3169(我的第一个查分约束!)
题目大意:有N头奶牛,编号从1到N,从左到右站成一排。有些奶牛互相喜欢,有些奶牛互相不喜欢。互相喜欢的奶牛有要求:互相喜欢的奶牛之间的距离不能超过一个值;同样,互相讨厌的奶牛之间的距离不能小于一个值。现在求在这样的要求下,1~N之间的距离的最大值。如果无法满足所有要求就输出-1,如果有无限种情况就输出-2,否则输出最大值。
输入: 输出:
4 2 1 27 1 3 10 2 4 20 2 3 3
解释:有四头牛,有两对互相喜欢,一对互相讨厌。两队喜欢的分别是1和3,要求距离不能大于10。另外一对是2,4,要求为20。讨厌的的一对是2,3,距离得不小于3。所以最大值为27。
(1和2的距离为7,2和3的距离为3,3和4的距离为17)
--->差分约束
那么现在来分析这道题。
假设互相喜欢的两头牛是a和b,那么dis[b]-dis[a]<=D(D为要求的值,dis[a]表示a到1的距离)
互相讨厌的是c和d,那么dis[d]-dis[c]>=D ----> dis[c]-dis[d]<=-D
因为距离是递增的,所以还有一个条件,s[i]-s[i-1]>=0 ----> s[i-1]-s[i]<=0
不等式已经列出来了,现在可以建图了。(详见代码)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int MAXN=1000+10; const int INF=0x3f3f3f3f; int n,ML,MD,cnt; int dis[MAXN],head[MAXN*MAXN],num[MAXN]; bool vis[MAXN]; struct node{ int v,w,next; }e[MAXN*MAXN]; int SPFA() { queue<int>q; memset(dis,INF,sizeof(dis)); memset(num,0,sizeof(num)); memset(vis,0,sizeof(vis)); q.push(1); dis[1]=0; num[1]=1; vis[1]=1; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v,w=e[i].w; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; if(!vis[v]){ if(++num[v]>n) return -1; } q.push(v); vis[v]=1; } } } if(dis[n]==INF) return -2; else return dis[n]; } void Add(int a,int b,int c) { e[cnt].v=b; e[cnt].w=c; e[cnt].next=head[a]; head[a]=cnt++; } int main(void) { while(~scanf("%d%d%d",&n,&ML,&MD)){ memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) Add(i,i-1,0); //升序 所以 s[i]-s[i-1]>=0 -> s[i-1]-s[i]<=0 //我们可以把s[i]近似的看做i for(int i=1,a,b,c;i<=ML;i++){ scanf("%d%d%d",&a,&b,&c); if(a>b) swap(a,b); Add(a,b,c); } //a like b,so b-a<=c -> b<=a+c for(int i=1,a,b,c;i<=MD;i++){ scanf("%d%d%d",&a,&b,&c); if(a>b) swap(a,b); Add(b,a,-c); } //the same b-a>=c -> a-b<=-c int ans=SPFA(); printf("%d\n",ans); } return 0; }//SnowCabbage