POJ 3169 Layout(差分约束+链式前向星+SPFA)

2022-11-24,,,,

描述

Like everyone else, cows like to stand close to their friends when queuing for feed. FJ has N (2 <= N <= 1,000) cows numbered 1..N standing along a straight line waiting for feed. The cows are standing in the same order as they are numbered, and since they can be rather pushy, it is possible that two or more cows can line up at exactly the same location (that is, if we think of each cow as being located at some coordinate on a number line, then it is possible for two or more cows to share the same coordinate).

Some cows like each other and want
to be within a certain distance of each other in line. Some really
dislike each other and want to be separated by at least a certain
distance. A list of ML (1 <= ML <= 10,000) constraints describes
which cows like each other and the maximum distance by which they may be
separated; a subsequent list of MD constraints (1 <= MD <=
10,000) tells which cows dislike each other and the minimum distance by
which they must be separated.

Your job is to compute, if
possible, the maximum possible distance between cow 1 and cow N that
satisfies the distance constraints.

输入

Line 1: Three space-separated integers: N, ML, and MD.

Lines
2..ML+1: Each line contains three space-separated positive integers: A,
B, and D, with 1 <= A < B <= N. Cows A and B must be at most D
(1 <= D <= 1,000,000) apart.

Lines ML+2..ML+MD+1: Each
line contains three space-separated positive integers: A, B, and D, with
1 <= A < B <= N. Cows A and B must be at least D (1 <= D
<= 1,000,000) apart.

输出

Line
1: A single integer. If no line-up is possible, output -1. If cows 1
and N can be arbitrarily far apart, output -2. Otherwise output the
greatest possible distance between cows 1 and N.

样例输入

4 2 1
1 3 10
2 4 20
2 3 3

样例输出

27

提示

Explanation of the sample:

There
are 4 cows. Cows #1 and #3 must be no more than 10 units apart, cows #2
and #4 must be no more than 20 units apart, and cows #2 and #3 dislike
each other and must be no fewer than 3 units apart.

The best layout, in terms of coordinates on a number line, is to put cow #1 at 0, cow #2 at 7, cow #3 at 10, and cow #4 at 27.

题意
有N头牛,按1-N排序,有ML对互相喜欢的牛,距离<=d,有MD对互相厌恶的牛,距离>=d,求牛1到牛N的最大距离,若不能按1-N排序(无解)输出-1,若1-N距离可以为无穷输出-2,其余输出1-N的距离
题解
这道题也是磨了很久才搞定的,对差分约束理解的不是很好
首先大致讲下差分约束
首先给你一堆式子
B-A<=c//1
C-B<=a//2
C-A<=d//3
求C-A的最大值
这里把1+2,得到C-A<=a+c//1
          C-A<=d    //2
这里可以看到,要同时满足1和2,就是max(C-A)=min(a+c,d)
我们看题目,通过题目可以写出下面几个不等式
Dist(J)-Dist(J-1)>=0(2<=j<=4) //1
Dist(3)-Dist(1)<=10                     //2
Dist(4)-Dist(2)<=20                     //3
Dist(3)-Dist(2)>=3          //4
这里把1和4做个变化,和23符号一致,得到

Dist(J-1)-Dist(J)<=0(2<=j<=4) //1
Dist(3)-Dist(1)<=10                     //2
Dist(4)-Dist(2)<=20                     //3

Dist(2)-Dist(3)<=-3         //4

对于满足像D[X]-D[Y]<=Z的情况,可以建立一条Y->X距离为Z的有向边,求1->N的最大值,就是求1->N的最短路径
如果满足像D[X]-D[Y]>=Z的情况,求1->N的最小值,就是求1->N的最长路径
 
解的存在性
差分约束存在3种情况
1.有解(直接输出Dist[n])
2.无解,出现负权圈,图内有两点之间有一个圈然后这个圈的权是负的,A-B和B-A的权都是负数(一个点的入队或者入栈次数>n就说明有负圈)(输出-1)
3.无穷多解,如果1到N根本不可达,就说明两者没有约束条件,可是是无穷多解(输出-2)
 
链式前向
这里讲一下链式前向星存图

const int N=,M=;
int head[N],cnt=;
struct edge
{
int v,w,next;
}edges[M];
void add(int u,int v,int w)
{
edges[cnt].v=v;
edges[cnt].w=w;
edges[cnt].next=head[u];
head[u]=cnt++;
}

上面这个意思是每次在链表结构里的首部存一条(u,v)权值为w的边,这个存储和输入方式是成逆序的,而且时间O(1),空间没有浪费

所以只需要i=head[u];i!=0;i=edges[i].next就可以访问所有从U出发的边

然后这道题就是建图,建完图跑最短路径,这里用SPFA可以判断负圈

代码
这里SPFA用栈来做了,当然用队列也可以

 #include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
#define INF 0x3f3f3f3f
const int N=,M=;
struct edge
{
int v,w,next;
}edges[M];
int Dist[N],Vis[N],head[N],In[N],cnt=;
void add(int u,int v,int w)
{
edges[cnt].v=v;
edges[cnt].w=w;
edges[cnt].next=head[u];
head[u]=cnt++;
}
int spfa(int n)
{
memset(Dist,INF,sizeof(Dist));
stack<int> st;
st.push();
Dist[]=;
while(!st.empty())
{
int u=st.top();st.pop();
Vis[u]=;
for(int i=head[u];i;i=edges[i].next)
{
int v=edges[i].v,w=edges[i].w;
if(Dist[v]>Dist[u]+w)
{
Dist[v]=Dist[u]+w;
if(Vis[v])continue;
Vis[v]=;
st.push(v);
if(++In[v]>n)return ;//一个点的入栈次数>n说明存在负圈,无解
}
}
}
return ;
}
int main()
{
int n,ml,md,a,b,c;
scanf("%d%d%d",&n,&ml,&md);
for(int i=;i<ml;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
for(int i=;i<md;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(b,a,-c);//差分约束
}
if(spfa(n)==)printf("-1\n");
else printf("%d\n",Dist[n]==INF?-:Dist[n]);
return ;
}

POJ 3169 Layout(差分约束+链式前向星+SPFA)的相关教程结束。

《POJ 3169 Layout(差分约束+链式前向星+SPFA).doc》

下载本文的Word格式文档,以方便收藏与打印。