man

Description
n间房子高度不同,Man 要从最矮的房子按照高度顺序跳到最高的房子,你知道房子的顺序,以及Man一次最远可以跳多远,相邻的房子至少有1的距离,房子的宽不计,现在由你安排相邻房子的距离,使Man可以跳到最高的房子且让最矮的房子与最高的房子距离最远,没有合法方案输出-1
Input
第一行一个整数T表示数据组数,每组数据第一行两个整数n,d分别表示房子数量以及Man一次可以跳多远,第二行n个整数用空格隔开,第i个整数表示第i个房子的高度
Output
每组数据输出‘Case ’+第几组数据+‘: ’+最远距离
Sample Input
样例输入:
3
4 4
20 30 10 40
5 6
20 34 54 10 15
4 2
10 20 16 13

样例输出:
Case 1: 3
Case 2: 3
Case 3: -1
HINT
数据范围:
对于40%的数据 n < 8 t=2 d < 10
对于100%的数据 n < 10001 d < 1000000 t < 100 高度 < 1000000


差分约束典型题…
关于如何理解 选取起点和终点中靠左边的点, 开始跑一遍最短路就可以得到答案, 这里提供一种思路: 在跑最短路之前, dis被设置为INF, 跑最短路的过程就是为了使dis满足约束条件. 只要跑完最短路, dis[t]必定就是最大的. 至于为什么要选取起点和终点中靠左的开始跑最短路, 理由是dis[t]维护的是s到t的距离的最大值. 这个假如t在s的左边, 则距离为负, 则维护的实际上是t到s的距离的最小值. 因此要确保起始遍历的点在终结点的左边.

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxN = 1000;
const int maxRoom = (int)1e6;
struct building
{
    int h, id;
}a[maxN];
int head[maxN];
int top;
struct edge
{
    int v, w, next;
}G[maxN << 2];
void addEdge(int u, int v, int w)
{
    G[top].v = v;
    G[top].w = w;
    G[top].next = head[u];
    head[u] = top ++;
}
int operator <(building x, building y)
{
    return x.h < y.h;
}
int dis[maxN];
int Q[maxRoom];
int inQ[maxN];
int vis[maxN];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("man.in", "r", stdin);
    freopen("man.out", "w", stdout);
    #endif
    ios::sync_with_stdio(false);
    int T, _case = 0;
    for(cin >> T; T; T --)
    {
        int n, d;
        cin >> n >> d;
        memset(head, - 1, sizeof(head));
        top = 0;
        for(int i = 0; i < n; i ++)
        {
            cin >> a[a[i].id = i].h;
            if(i)
                addEdge(i, i - 1, - 1);
        }
        sort(a, a + n);
        for(int i = 1; i < n; i ++)
        {
            int u = a[i - 1].id, v = a[i].id;
            if(u > v)
                swap(u, v);
            addEdge(u, v, d);
        }
        int L = 0, R = 1, s = a[0].id, t = a[n - 1].id;
        if(s > t)
            swap(s, t);
        Q[L] = s;
        memset(dis, 127, sizeof(dis));
        dis[s] = 0;
        memset(inQ, 0, sizeof(inQ));
        inQ[s] = 1;
        memset(vis, 0, sizeof(vis));
        vis[s] = 1;
        int flag = 0;
        while(L < R)
        {
            int u = Q[L];
            for(int i = head[u]; i != - 1; i = G[i].next)
            {
                int v = G[i].v;
                if(dis[u] + G[i].w >= dis[v])
                    continue;
                dis[v] = dis[u] + G[i].w;
                if(! inQ[v])
                {
                    inQ[v] = 1;
                    Q[R ++] = v;
                    vis[v] ++;
                    if(vis[v] > n)
                    {
                        flag = 1;
                        break;
                    }
                }
            }
            inQ[u] = 0;
            L ++;
        }
        if(flag)
            printf("Case %d: -1\n", ++ _case);
        else
            printf("Case %d: %d\n", ++ _case, abs(dis[t]));
    }
}

转载于:https://www.cnblogs.com/ZeonfaiHo/p/6402843.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值