• Layout「差分约束」


    Layout「差分约束」

    题目描述

    和人类一样,奶牛们在打饭的时候喜欢和朋友站得很近。约翰的编号为 1nn(2<=n<=1000) 只奶牛正打算排队打饭。现在请你来安排她们,让她们在数轴上排好队。奶牛的弹性很好,同一个坐标可以站无限只奶牛,排队的顺序必须和她们编号的顺序一致。有 M 对奶牛互相爱慕,她们之间的距离不能超过一定的值,有 K对奶牛互相敌视,她们的距离不能小于一定的值 那么,首尾奶牛的最大距离是多少呢?

    输入

    第一行输入 n,M,K,(0<M,K<=5000)。

    接下来 M行每行三个整数x,y,z,表示编号为 xy 的两头奶牛之间的距离最大不超过 z

    再接下来 K行每行三个整数 a,b,c,表示编号为 ab 的两头奶牛之间的距离最少为c

    输出

    如果没有合理方案,输出 −1,如果首尾两头牛的距离可以无限大,输出 −2,否则输出一个整数表示首尾奶牛的最大距离。

    样例

    样例输入

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

    样例输出

    27


    思路分析

    裸的差分约束,已经忘得一干二净

    • 通过题目中给出的信息显然我们可以得出形如xi - xj < a的关系,这样就成了一道裸的差分约束的题
    • 另外这题还需要建立一个超级原点,来判断图是否联通或有无负权环,因为1可能无法到达所有点

    差分约束基本思路

    • 给定n个变量和m个不等式,每个不等式形如xi−xj≤w,求xn−1−x0 的最大值。(0 <= i, j < n)

    • 举个栗子:

      x2x1a1

      x3x2a2

      x4x3a3

      x5x4a4

    比方说我们有以上几个不等式,求 x5x1的最大值,直接代入计算就可以,但是要计算机能拿来计算,我们得有一个规矩点的方法

    我们可以通过移项,发现 xixj+ak 然后可以自然而然地想到求最短路时的松弛操作(xi被松弛,作为边的终点),但是这里符号是反的,这并无大碍,因为我们是求 x5x1 的最大值,就等于 x1~x5 的最小值(因为要保证所有不等式都成立,同小取小),如果 dis[n] 是无穷大,就表明 x5x1 可以无穷大,如果出现负环,就表明无解

    • 因为存在负环,所以我们用spfa来跑最短路

    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int n,m,k;
    const int maxn = 1e3+10,maxm = 2e4+10,inf = 0x3f3f3f3f;
    int head[maxn],dis[maxn],vis[maxn],cnt[maxn];
    struct edge{
    	int to,next,w,flag;
    }e[maxm];
    int len = 0;
    void addedge(int u,int v,int w){
    	e[++len].to = v;
    	e[len].w = w;
    	e[len].next = head[u];
    	head[u] = len;
    }
    int spfa(int x){ 
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	memset(cnt,0,sizeof(cnt));
    	queue<int>q;
    	dis[x]=0;
    	q.push(x);
    	while(!q.empty()){
    		int u = q.front();q.pop();
    		vis[u]=0;
    		for(int i = head[u];~i;i = e[i].next){
    			int v = e[i].to,w = e[i].w;
    			if(dis[v]>dis[u]+w){
    				dis[v] = dis[u]+w;
    				if(!vis[v]){
    					vis[v] = 1;
    					q.push(v);
    					cnt[v]++; //cnt记录松弛次数
    					if(cnt[v]>n)return -1; //存在负环,无解
    				}
    			}
    		}
    	}
    	if(dis[n]==inf)return -2;//未被松弛,说明距离可以无限大
    	return dis[n]; //x1-xn的最小值,即为xn-x1的最大值
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&k);
    	memset(head,-1,sizeof(head));
    	for(int i = 1;i <= m;i++){
    		int u,v,w;scanf("%d%d%d",&u,&v,&w);
    		if(u>v)swap(u,v);
    		addedge(u,v,w);
    	}
    	for(int i = 1;i <= k;i++){
    		int u,v,w;scanf("%d%d%d",&u,&v,&w);
    		if(u>v)swap(u,v); 
    		addedge(v,u,-w); //这里由原来的xi-xj>=a改为xj-xi<=-a,即xj<=-a+xi,那么我们就从v到u反过来建一条权值为负的边
    	}
    	for(int i = 1;i <= n;i++){
    		addedge(i+1,i,0); //这题的一个坑,相邻节点要建边,因为牛必须按编号相邻
    	}
    	for(int i = 1;i <= n;i++){
    		addedge(0,i,0); //建一个超级原点保证与所有节点相连
    	}
    	if(spfa(0)==-1){ //有无解从超级原点开始判断
    		printf("-1");
    		return 0;
    	}
    	printf("%d",spfa(1));//有解,求最大值
    	return 0;
    }
    
    
  • 相关阅读:
    超越自我的事
    ENVI/SARscape软件概述及安装
    《万万没想到:用理工科思维理解世界》读书简记
    Ruby on Rails 搭建环境 (ubuntu)
    拓荒者
    Rails 画类图的几个方法
    ERROR: Error installing mysql2: ERROR: Failed to build gem native extension [@Ubuntu 15.04]
    无题20150105
    关于Unity中Camera的Aspect
    Esfog_UnityShader教程_逐帧动画
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13323954.html
Copyright © 2020-2023  润新知