http://acm.hdu.edu.cn/showproblem.php?pid=3592
题意:有N个人按照1-N 的顺序排成一排,给你X个关于他们位置的关系,如:a, b ,c,则说明编号为a的人在标号为b 的人的前面,且两人最多相隔c距离,再给你Y给位置关系,给出的是a和b两个人至少相距c,问1号人和N号人最远相距多少。如果不存在这样的排序,则输出-1 ,如果1和N可以相距任意的距离,则输出-2, 否则输出最长的距离。
思路:差分约束。这题差分约束很好想,图的边只要有两类:X+Y个题目的约束,N个前面两个人的约束(因为顺序是1 -- N)。还有需要注意的是输出:若原图有负环,则输出-1,若最后的距离是inf,则输出-2 , 否则输出距离。
代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
const int inf = (1<<30) ;
const int MAXN = 1010 ;
int T ,N,X,Y;
struct node{
int num ,nx, dis ;
}edge[22000] ;
int root[MAXN] , cnt ;
void add(int a, int b, int c){
edge[cnt].num = b ;
edge[cnt].nx = root[a] ;
edge[cnt].dis = c ;
root[a] = cnt++ ;
}
void init(){
memset(root , -1, sizeof(root));
cnt = 0 ;
}
std::queue<int> que ;
int dis[MAXN] , in[MAXN] ;
bool vis[MAXN] ;
bool relax(int u ,int v, int d){
if(dis[v] > dis[u] + d){
dis[v] = dis[u] + d ;
return 1;
}
return 0 ;
}
bool spfa(){
for(int i=1;i<=N;i++){
in[i] = 0 ;
vis[i] = 0 ;
dis[i] = inf ;
}
while(!que.empty()) que.pop() ;
dis[1] = 0 ;
vis[1] = 1 ;
in[1] = 1;
que.push(1) ;
while(!que.empty()){
int u = que.front() ; que.pop() ;
vis[u] = 0 ;
for(int i=root[u] ;i!=-1; i=edge[i].nx){
int v = edge[i].num ;
int d = edge[i].dis ;
if(1 == relax(u,v,d) && !vis[v]){
vis[v] = 1 ;
in[v] ++ ;
if(in[v] > sqrt(N*1.0) ) return false ;
que.push(v) ;
}
}
}
return true ;
}
int main(){
int a,b,c ;
scanf("%d",&T);
while(T--){
scanf("%d %d %d",&N,&X,&Y);
init() ;
for(int i=1;i<=X;i++){
scanf("%d %d %d",&a,&b,&c);
add(a,b,c);
}
for(int i=1;i<=Y;i++){
scanf("%d %d %d",&a,&b,&c);
add(b,a,-c) ;
}
for(int i=2;i<=N;i++){
add(i,i-1,0);
}
if( spfa() ){
if(dis[N] == inf)
printf("-2\n");
else
printf("%d\n",dis[N]);
}
else{
printf("-1\n");
}
}
return 0 ;
}
差分约束的总结和心得:
1、差分约束的题目通常是在满足一组线性方程组的情况下求出满足条件的解,或是判断解的存在性;
2、解题的关键是建图,并由spfa求解。