差分约束 POJ 3169 Layout

题意:

将给定的n头牛按编号大小依次安排在数轴上

给出ml条边,每条边A、B、D表示牛A和牛B的距离不能超过D

再给出md条边,每条边A、B、D表示牛A和牛B的距离不能低于D

求符合要求的最大的牛1到牛n的距离。

题解:

一堆不等式,首先想到差分约束。

差分约束:

要求最大值,则将不等式组转换为小于等于形式,spfa求最短路(因为可能有负环),dis初始化为INF,对于每个形如 x_{i}-x_{j}\leqslant k  的不等式,可得一条j号节点指向i号节点权值为k的有向边

要求最小值,则将不等式组转换为大于等于形式,spfa求最长路,dis初始化为0(或负无穷?具体看题目),对于每个形如 x_{i}-x_{j}\geqslant k 的不等式,可得一条
j号节点指向i号节点权值为k的有向边

本题要求最大值。

不等式转换过程中注意本题的隐含条件,编号大的坐标一定大于等于编号小的坐标,所以对于不超过D的边,不等式为x_{B}-x_{A}\leqslant D ,对于不低于D的边,不等式为 x_{A}-x_{B}\leqslant -D

最后spfa求最短路,若有负环,说明无解,输出-1;若从1到n的最短距离为INF,说明无限多解,输出-2;否则,输出最短距离。

代码:

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
#define ll long long
#define db double
#define m_p make_pair
#define p_b push_back
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mst(a,b) memset(a,b,sizeof(a))
const int MAXN=1e3+5;
const db eps=1e-8;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int seed=131;
int n,ml,md;
struct Edge{
	int v,w;
	Edge(int _v=0,int _w=0):v(_v),w(_w){}
};
vector<Edge> G[MAXN];
bool vis[MAXN];
queue<int> q;
int dis[MAXN],cnt[MAXN];
bool spfa(int s,int n){
	mst(vis,0);
	mst(dis,INF);
	mst(cnt,0);
	vis[s]=1;
	q.push(s);
	dis[s]=0;
	cnt[s]=1;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=0;i<G[u].size();i++){
			Edge &tt=G[u][i];
			int v=tt.v,w=tt.w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				cnt[v]++;
				if(!vis[v]) vis[v]=1,q.push(v);
				if(cnt[v]>n) return true;
			}
		}
	}
	return false;
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d %d %d",&n,&ml,&md);
	int u,v,d;
	for(int i=1;i<=ml;i++){
		scanf("%d %d %d",&u,&v,&d);
		G[u].p_b(Edge(v,d));
	}
	for(int i=1;i<=md;i++){
		scanf("%d %d %d",&u,&v,&d);
		G[v].p_b(Edge(u,-d));
	}
	bool f=spfa(1,n);
	if(f) cout<<"-1\n";
	else if(dis[n]==INF) cout<<"-2\n";
	else  cout<<dis[n]<<"\n";
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38515845/article/details/89764092
今日推荐