POJ3169:Layout(差分约束)
http://poj.org/problem?id=3169
题意:
一堆牛在一条直线上按编号站队,在同一位置可以有多头牛并列站在一起,但编号小的牛所占的位置不能超过编号大的牛所占的位置,这里用d[i]表示编 号为i的牛所处的位置,即要满足d[i]-d[i+1]<=0,同时每两头牛之间有以下两种关系(对于输入的a b d来说):
1>如果是喜欢关系:即需要满足d[b]-d[a]<=d
2>如果是讨厌关系:即需要满足d[b]-a[a]>=d ……> d[a]-d[b]<=-d
由于题目要求队伍的最大可能长度,即求满足以下三个约束条件的最大值,,由于此处是求最大值,故用Bellman_Ford算法求约束图的最短路径.
1>对于ML有:d[b]-d[a]<=d
2>对于MD有:d[a]-d[b]<=-d
3>对于n个顶点的约束图有:s[i]-s[i+1]<=0(隐含条件)
题目的解为:有负环输出-1,d[n]无穷大输出-2,其他输出dist[n].
在差分约束系统中如果题目要求是求最小值,就将约束条件转化为">="形式,然后用Bellman_Ford算法求解约束图的最长路径,如果题目要
求的是最大值,就将约束条件转化为"<="形式,然后用Bellman_Ford算法求解约束图的最短路径.
PS:
(1)INF不能开得太大,可能会溢出;
(2)数组尽量开小,不然会比较慢
如果有负环,输出-1,如果N可以无限远,即1与N不连通,输出-2,其他情况输出1与N的最大距离。(最短路)
#include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <queue> #define N 1000001 using namespace std; int n,m,k,tt; int head[1001],v[1001],dis[1001]; struct node { int x,y,z; int next; } q[1000001]; void init() { memset(head,-1,sizeof(head)); tt=0; } void add(int xx,int yy,int zz) { q[tt].x=xx; q[tt].y=yy; q[tt].z=zz; q[tt].next=head[xx]; head[xx]=tt++; } void SPFA() { for(int i=1; i<=n; i++) { dis[i]=N; v[i]=0; } dis[1]=0; v[1]=1; queue<int>p; p.push(1); while(!p.empty()) { int ff=p.front(); p.pop(); v[ff]=0; for(int i=head[ff]; i!=-1; i=q[i].next) { if(dis[q[i].y]>dis[ff]+q[i].z) { dis[q[i].y]=dis[ff]+q[i].z; if(dis[q[i].y]<0)//不存在最短路(这题是实际问题,不会出现负边//或者根据有顶点入队列的次数大于n) { printf("-1\n"); return ; } if(!v[q[i].y]) { v[q[i].y]=1; p.push(q[i].y); } } } } if(dis[n]==N) printf("-2\n");//1到n没有路 else printf("%d\n",dis[n]); return ; } int main() { int xx,yy,zz; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { init(); for(int i=1; i<=m; i++) { scanf("%d%d%d",&xx,&yy,&zz); add(xx,yy,zz); } for(int i=1; i<=k; i++) { scanf("%d%d%d",&xx,&yy,&zz); add(yy,xx,-zz); } for(int i=1; i<n; i++)//隐含条件 { add(i+1,i,0); } SPFA(); } return 0; }