POJ3169-Layout
知识点-差分约束
上题目POJ3169
例题
题目描述
n头牛编号为1到n(2<=n<=1000) ,按照编号的顺序排成一列,每两头牛的之间的距离 >= 0。这些牛的距离存在着一些约束关系:1.有ml组(u, v, w)的约束关系,表示牛[u]和牛[v]之间的距离必须 <= w。2.有md组(u, v, w)的约束关系,表示牛[u]和牛[v]之间的距离必须 >= w。问如果这n头无法排成队伍,则输出-1,如果牛[1]和牛[n]的距离可以无限远,则输出-2,否则则输出牛[1]和牛[n]之间的最大距离。
输入
第1行,3个整数,N,ML,MD
第2至ML+1行,3个整数,A, B, D,其中1 <= A < B <= N. 牛A,B距离最多为D (1 <= D <= 1,000,000)
第ML+2至ML+MD+1行,三个整数,A, B, D, 其中 1 <= A < B <= N. 牛A,B距离最少为D (1 <= D <= 1,000,000)
输出
一个整数
如果在上述条件下,奶牛站不成一排,则输出"-1",如果能站成一排,但是第1头牛~第N头牛的距离无限远,则输出"-2",如果满足条件,并且第1头牛~第N头牛之间存在实际距离,则输出第1头牛~到第N头牛之间的能达到的最远距离。
样例输入
4 2 1
1 3 10
2 4 20
2 3 3
样例输出
27
分析
本题求的是最大差,也就是最短路。然而给出的约束条件既有a-b<=k,又有a-b>=k的形式。我们只需要a-b<=k,那么对于a-b>=k,我们可以把它转换成b-a<=-k。
然而貌似有这两个约束条件还不够用!根据题目描述:每两头牛距离大于等于0。我们不难得到第三个约束条件:(i+1)-i>=0,也就是i-(i+1)<=0。
将三个约束条件再一一列出:
a-b<=k
b-a<=-k
i-(i+1)<=0
本题还必须判断有无解以及距离是不是无限大。对于有无解只需要判断负边权环,如果节点入队次数超过总节点数就说明存在负边权环;距离无限大就更好判断不说了。
代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct p{ int to,v,nxt; }edge[150015]; long long n,cnt,ml,md,a,b,d,dis[150015],c[150015],queue[150015],heads[150015],head,tail; bool vis[150015]={0}; int addEdge(int u,int v,int val) { edge[++cnt].to=v; edge[cnt].v=val; edge[cnt].nxt=heads[u]; heads[u]=cnt; } int spfa() { for(int i=1;i<=n;++i) dis[i]=0x7fffffff; dis[1]=0;queue[1]=1;head=0;tail=1;vis[1]=1; while(head<=tail) { int node=queue[++head]; vis[node]=0; for(int i=heads[node];i!=0;i=edge[i].nxt) { int to=edge[i].to,val=edge[i].v; if(dis[to]>dis[node]+val) { dis[to]=dis[node]+val; if(!vis[to]) { queue[++tail]=to; vis[to]=1; if(++c[to]>n)return 1; } } } } return 0; } int main() { scanf("%d%d%d",&n,&ml,&md); for(int i=1;i<=ml;i++) { scanf("%d%d%d",&a,&b,&d); addEdge(a,b,d); } for(int i=1;i<=md;i++) { scanf("%d%d%d",&a,&b,&d); addEdge(b,a,-d); } for(int i=1;i<n;i++) addEdge(i+1,i,0); if(spfa())printf("-1\n"); else if(dis[n]>=0x7fffffff)printf("-2\n"); else printf("%d\n",dis[n]); }
posted on 2017-04-18 14:04 Skype_lorenzo 阅读(111) 评论(0) 编辑 收藏 举报