HDU 3440 House Man (差分约束)

题意:有N个在一条直线上的房子, 每个房子有着不同的高度,超人可以将这些房子左右移动,但不能改变房子之间的相对位置。超人要从最矮的房子跳到刚好比他高的房子上面, 且每次跳的房子都要比当前房子要高,他要跳N-1次。那么最后超人肯定会跳到最高的房子上面,现在给出超人一次能够跳的最远距离D,求如何摆放这些房子, 使得超人能够经过所有的房子跳到最高的房子, 又要使最矮的房子和最高的房子之间的距离最远,输出最远距离。

题解:差分约束
求最远距离,跑最短路即可。我们用 d [ i ] d[i] d[i]表示离起点的距离。

由于不改变房子固有顺序,可得约束方程:
d [ i − 1 ] − d [ i ] < = − 1 d[i-1]-d[i]<=-1 d[i1]d[i]<=1

然后考虑跳的顺序,因为两个房子间距离不能超过D,我们排序后根据id大小设置约束即可。

同时也要考虑起点和终点的id大小,因为最终结果是正的,所以起点的id要小于终点,不用考虑从低跳到高还是从高跳到低。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
#define pii pair<int, int>
using namespace std;
const int maxn = 1e3 + 5;
int t, n, D;
struct node1 {
    
    
	int h, id;
	bool operator<(const node1 x)const {
    
    
		return h < x.h;
	}
}h[maxn];
struct node {
    
    
	int v, nxt, w;
}edge[maxn << 2];
int vis[maxn], d[maxn], head[maxn], mark[maxn], k, s;
void add(int u, int v, int w) {
    
    
	edge[++k].nxt = head[u];
	edge[k].v = v;
	edge[k].w = w;
	head[u] = k;
}
bool spfa() {
    
    
	for (int i = 1; i <= n; i++) {
    
    
		vis[i] = mark[i] = 0;
		d[i] = 0x3f3f3f3f;
	}
	queue<int>q;
	q.push(s);
	mark[s] = vis[s] = 1;
	d[s] = 0;
	while (!q.empty()) {
    
    
		int u = q.front(); q.pop();
		vis[u] = 0;
		for (int i = head[u]; i; i = edge[i].nxt) {
    
    
			int v = edge[i].v, w = edge[i].w;
			if (d[v] > d[u] + w) {
    
    
				d[v] = d[u] + w;
				if (vis[v]) continue;
				vis[v] = 1;
				if(++mark[v] > n) return false;  //负环 n+1以上才有负环
				q.push(v);
			}
		}
	}
	return true;
}

int main() {
    
    
	int cas = 0;
	scanf("%d", &t);
	while (t--) {
    
    
		k = 0;
		memset(head, 0, sizeof(head));
		scanf("%d%d", &n, &D);
		for (int i = 1; i <= n; i++) {
    
    
			scanf("%d", &h[i].h);
			h[i].id = i;
			if (i != 1) add(i, i - 1, -1);
		}
		sort(h + 1, h + n + 1);
		for (int i = 2; i <= n; i++) {
    
    
			if (h[i].id > h[i - 1].id) add(h[i - 1].id, h[i].id, D);
			else add(h[i].id, h[i - 1].id, D);
		}
		s = min(h[1].id, h[n].id);
		if (spfa()) printf("Case %d: %d\n", ++cas, d[max(h[1].id, h[n].id)]);
		else printf("Case %d: %d\n", ++cas, -1);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/108757913
今日推荐