题意:有N个在一条直线上的房子, 每个房子有着不同的高度, 一个超人可以将这些房子左右移动但不能改变房子之间的相对位置.现在超人要从最矮的房子跳到刚好比他高的房子上面, 且每次跳的房子都要比当前房子要高.那么最后超人肯定会跳到最高的房子上面, 现在给出超人能够跳的最远距离, 问: 如何摆放这些房子, 使得超人能够经过所有的房子跳到最高的房子, 又要使最矮的房子和最高的房子之间的距离最远(指房子在直线上的距离,不是走的路)??
看sample说明问题
sample3
4 2
10 20 16 13
超人从10开始,跳到13,但是10和13的水平距离至少为3,但超人的水平限制距离是2,所以无论怎么移动都无法跳过去,输出-1
看sample1
4 4
20 30 10 40
我们先给这些屋子,按横坐标给他们标号
20(1) 30(2) 10(3) 40(4)
所以我们可以描述为,超人跳跃的顺序为3 --->1---->2---->4,那么我们要求的就是3号点和4号点的最远距离(前提是要保证超人能完成整个跳跃)
另外超人的跳跃是按照高度来的,所以超人跳跃的路径其实是唯一确定的。要超人完成整个跳跃,就要保证超人能从“当前点”跳向“下一个点”,所以两点的水平距离有一个限制
| "下一个点的坐标" - “当前点的坐标” | <= lim ,这里有一个绝对值,因为表示的是距离,所以我们可以约定一下,消去绝对值
d[v] <= d[u]+lim ,其中点v的坐标大于点u的坐标
再看sample1:
要从10(3)跳到20(1)
| 点3的坐标 - 点1的坐标| <= lim ,约定为 d[3] - d[1] <= lim ----> d[3] <= d[1] + lim ---->因而建立的有向边为 <1,3> , w = lim
要从30(2)跳到40(4)
|点2的坐标 - 点4的坐标| <= lim , 约定为 d[4] - d[2] <= lim ----> d[4] <= d[2] + lim ----->因而建立有向边<2,4> , w = lim
另外还别漏了一点,对于相邻的两个点,它们的距离至少为1
例如
30(2) 10(3)
这两个点要满足 d[3] - d[2] >= 1 ---> d[2] - d[3] <= -1 ---> d[2] <= d[3] + (-1) ----> 建立有向边 <3,2> , w = -1
这样就建立了图,例如sample,我们就是要求点3到点4的最短路
还注意一点,因为我们建图的时候是约定好的,有向边都是 标号小的点 ---> 标号大的点(除开边权为-1的边),所以我们找最短路的时候也要约定从标号小的点 到 标号大的点
如果 起点标号 > 终点标号 , 则反过来求最短路
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1005;
int dis[maxn], head[maxn], time[maxn], cnt;
bool vis[maxn];
struct Edge
{
int to, w, next;
}edge[2005];
struct House
{
int hei, id;
}hou[maxn];
bool cmp(House p, House q)
{
return p.hei < q.hei;
}
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int spfa(int s, int en, int n)
{
memset(dis, 63, sizeof(dis));
memset(vis, false, sizeof(vis));
memset(time, 0, sizeof(time));
dis[s] = 0;
vis[s] = true;
time[s]++;
queue<int> q;
q.push(s);
while(!q.empty())
{
int tem = q.front();
q.pop();
vis[tem] = false;
for(int i = head[tem]; i != -1; i = edge[i].next)
{
int to = edge[i].to;
if(dis[tem] + edge[i].w < dis[to])
{
dis[to] = dis[tem] + edge[i].w;
if(!vis[to])
{
q.push(to);
vis[to] = true;
time[to]++;
if(time[to] >= n)
{
return -1;
}
}
}
}
}
return dis[en];
}
int main()
{
int T, n, dis, ca = 1;
cin >> T;
while(T--)
{
cin >> n >> dis;
cnt = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i <= n; i++)
{
scanf("%d", &hou[i].hei);
hou[i].id = i;
if(i >= 2)
add_edge(i, i - 1, -1);
}
sort(hou + 1, hou + n + 1, cmp);
for(int i = 1; i < n; i++)
{
int u = hou[i].id;
int v = hou[i+1].id;
if(u > v)
swap(u, v);
add_edge(u, v, dis);
}
int s = hou[1].id;
int en = hou[n].id;
if(s > en)
swap(s, en);
int ans = spfa(s, en, n);
printf("Case %d: ", ca++);
if(ans == -1)
cout << -1 << endl;
else
cout << ans << endl;
}
return 0;
}