Layout
题目链接:
http://poj.org/problem?id=3169
解题思路:
题目大意:
当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂
食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,
如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。
一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间
的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。
(1<=ML,MD<=10000,1<=L,D<=1000000)
你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号奶牛间的距离可以任意大,输出-2;否则,计算出在满足所
有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。
算法思想:
我们先研究,如果不要求输出1和N的最大距离,而只需一个可行的距离,应该如何操作。
我们用D[i]表示I号奶牛和1号奶牛间的距离。
因为在队伍中的顺序必须和编号相同,所以对于任意I号奶牛,1<=I<N,在距离上应该满足:
D[I+1] - D[I] >= 0
对于每个好感的描述(i,j,k),假设i<=j,体现到距离上的要求就是:
D[j] - D[I] <= k
对于每个反感的描述(i,j,k),假设i<=j,体现到距离上的要求就是:
D[j] - D[I] >= k
这时的模型有一个名称,叫作:差分约束系统。
为了方便起见,我们将每种不等式写成我们约定的形式:
D[I] <= D[I+1]
D[j] <= D[I] + k
D[I] <= D[j] - k
看到这些不等式,你想到了什么?
没错,在求顶点间地最短路问题中,我们有这样的不等式:
若顶点u到顶点v有边e=uv,且边权为w(e),设d(u),d(v)为源点到顶点u和顶点v的最短路长,
则 d(v) <= d(u) + w(e)
这个不等式和前面的条件形式十分相似,这就启发我们用构图用最短路做。
具体步骤是:
作有向图G=(V,E),V={ v1,v2,v3,…,vn},E={e1,e2,e3,…},对于相邻两点i和(i+1),对应的顶点vi+1向vi引一条边,费用
为0;对于每组好感描述(ai,bi,di),我们假设有ai<bi,否则ai和bi交换,则顶点vai向vbi引一条边,费用为di;对于每组反感描述
(ai,bi,di),我们假设有ai<bi,否则ai和bi交换,则顶点vbi向vai引一条边,费用为-di。
于是问题变为在G中求v1到其它所有顶点的最短路。我们证明若G中无负权回路,则问题有解,即存在满足条件的数列,若G中有负
权回路,则问题无解,即不存在满足条件的数列。
AC代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define INF 0xfffffff
using namespace std;
const int V=1010;
const int E=20010;
int n,ml,md;
int pnt[E],cost[E],nxt[E];
int e,head[V],dis[V];
int vis[V];
int cnt[V];
int relax(int u,int v,int c){
if(dis[v] > dis[u]+c){
dis[v] = dis[u]+c;
return 1;
}
return 0;
}
inline void addedge(int u,int v,int c){
pnt[e] = v;
cost[e] = c;
nxt[e] = head[u];
head[u] = e++;
}
int SPFA(int src,int n){
memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
for(int i = 1; i <= n; ++i)
dis[i] = INF;
dis[src] = 0;
queue<int> q;
q.push(src);
vis[src] = 1;
++cnt[src];
while(!q.empty()){
int u,v;
u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = nxt[i]){
v = pnt[i];
if(relax(u,v,cost[i]) && !vis[v]){
q.push(v);
vis[v] = 1;
if(++cnt[v] > n)
return -1;
}
}
}
if(dis[n] == INF)
return -2;
return dis[n];
}
int main(){
while(~scanf("%d%d%d",&n,&ml,&md)){
int a,b,c;
e = 0;
memset(head,-1,sizeof(head));
for(int i = 0; i < ml; ++i){
scanf("%d%d%d",&a,&b,&c);
if(a > b)
swap(a,b);
addedge(a,b,c);
}
for(int i = 0; i < md; ++i){
scanf("%d%d%d",&a,&b,&c);
if(a < b)
swap(a,b);
addedge(a,b,-c);
}
printf("%d\n",SPFA(1,n));
}
return 0;
}