1. 程式人生 > >HDU 3440 House Man(編號排序+線性差分約束跑最短路)

HDU 3440 House Man(編號排序+線性差分約束跑最短路)

House Man

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3605    Accepted Submission(s): 1517


Problem Description In Fuzhou, there is a crazy super man. He can’t fly, but he could jump from housetop to housetop. Today he plans to use N houses to hone his house hopping skills. He will start at the shortest house and make N-1 jumps, with each jump taking him to a taller house than the one he is jumping from. When finished, he will have been on every house exactly once, traversing them in increasing order of height, and ending up on the tallest house.
The man can travel for at most a certain horizontal distance D in a single jump. To make this as much fun as possible, the crazy man want to maximize the distance between the positions of the shortest house and the tallest house.
The crazy super man have an ability—move houses. So he is going to move the houses subject to the following constraints:
1. All houses are to be moved along a one-dimensional path.
2. Houses must be moved at integer locations along the path, with no two houses at the same location.
3. Houses must be arranged so their moved ordering from left to right is the same as their ordering in the input. They must NOT be sorted by height, or reordered in any way. They must be kept in their stated order.
4. The super man can only jump so far, so every house must be moved close enough to the next taller house. Specifically, they must be no further than D apart on the ground (the difference in their heights doesn't matter).
Given N houses, in a specified order, each with a distinct integer height, help the super man figure out the maximum possible distance they can put between the shortest house and the tallest house, and be able to use the houses for training.  

 

Input In the first line there is an integer T, indicates the number of test cases.(T<=500)
Each test case begins with a line containing two integers N (1 ≤ N ≤ 1000) and D (1 ≤ D ≤1000000). The next line contains N integer, giving the heights of the N houses, in the order that they should be moved. Within a test case, all heights will be unique.  

 

Output For each test case , output “Case %d: “first where d is the case number counted from one, then output a single integer representing the maximum distance between the shortest and tallest house, subject to the constraints above, or -1 if it is impossible to lay out the houses. Do not print any blank lines between answers.  

 

Sample Input 3 4 4 20 30 10 40 5 6 20 34 54 10 15 4 2 10 20 16 13  

 

Sample Output Case 1: 3 Case 2: 3 Case 3: -1  

 

Author jyd  

 

Source 2010 ACM-ICPC Multi-University Training Contest(1)——Host by FZU   題目意思:
n個房子,線性一維排列,房子有高度,房子不能在同一個位置,現在有一個超人,從最低的房子開始跳,
每次跳的房子的高度要求比上一個房子的高度高,每個房子都要跳,最後要停在最高的房子上
你可以隨意改變任意房子之間的距離,但是不能改變房子的相對位置
每次超人最多跳D遠,問你超人跳完之後
最低的房子和最高的房子之間的距離最大可以是多少? 分析:
每次要求跳的高度遞增且要是最高的房子結束
說明跳的房子的順序已經排列好了
給線性一維上的房子編個號,1到n
按照高度升序排序,得到的編號順序就是跳的順序 假設x[i]:表示房子i的位置
x[i]-x[j]表示房子i和j之間的距離,i>j
比如樣例1
高度:20 30 10 40
編號:1  2  3  4
按照高度升序排序之後,跳的順序為:3 1 2 4
對每次跳:
x[3]-x[1]<=d
x[2]-x[1]<=d
x[4]-x[2]<=d
注意每次都是編號大的房子位置減去編號小的房子位置,這樣才能得到兩者間的距離 隱藏關係:同一個位置不能有兩個房子
則:x[i]-x[i-1]>=1,i屬於2到n
變形一下:x[i-1]-x[i]<=-1
現在所有的約束關係是都是這個形式:x[i]-x[j]<=x
開始建圖,j->i 權值為x
比如上面的樣例:
1->3 權值4
11->2 權值4
2->4 權值4
2->1 權值-1
3->2 權值-1
題目要求是從最低的房子到最高的房子的最大距離
注意:是最高房子和最低房子中編號小的房子出發,做起點
最高房子和最低房子中編號大的房子結束,做終點
因為高的房子編號不一定大,低的房子編號不一定小
然後因為表示式是x[i]-x[j]<=x
所以是求最短路,不能使用dj,因為存在負權
推薦使用spfa code:
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
#include<set>
#include<map>
#include<list>
#include<math.h>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
#define INF 9999999999
#define me(a,x) memset(a,x,sizeof(a))
int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31};
int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31};
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};

int getval()
{
    int ret(0);
    char c;
    while((c=getchar())==' '||c=='\n'||c=='\r');
    ret=c-'0';
    while((c=getchar())!=' '&&c!='\n'&&c!='\r')
        ret=ret*10+c-'0';
    return ret;
}
void out(int a)
{
    if(a>9)
        out(a/10);
    putchar(a%10+'0');
}

#define max_v 1005
struct node
{
    int v;
    LL w;
    node(int vv=0,LL ww=0):v(vv),w(ww) {}
};
struct node1
{
    int id,v;
}p[max_v];
bool cmp(node1 a,node1 b)
{
    return a.v<b.v;
}
LL dis[max_v];
int vis[max_v];
int cnt[max_v];
vector<node> G[max_v];
queue<int> q;

void init()
{
    for(int i=0; i<max_v; i++)
    {
        G[i].clear();
        dis[i]=INF;
        vis[i]=0;
        cnt[i]=0;
    }
    while(!q.empty())
        q.pop();
}

int spfa(int s,int n)
{
    vis[s]=1;
    dis[s]=0;
    q.push(s);
    cnt[s]++;

    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;

        for(int j=0; j<G[u].size(); j++)
        {
            int v=G[u][j].v;
            LL w=G[u][j].w;

            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(vis[v]==0)
                {
                    q.push(v);
                    cnt[v]++;
                    vis[v]=1;

                    if(cnt[v]>n)
                        return 0;
                }
            }
        }
    }
    return 1;
}
int f(int u,int v)
{
    for(int j=0; j<G[u].size(); j++)
    {
        if(G[u][j].v==v)
            return 0;
    }
    return 1;
}
int main()
{
    int t,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        int n,d;
        scanf("%d %d",&n,&d);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&p[i].v);
            p[i].id=i;
        }
        sort(p+1,p+1+n,cmp);
        init();
        int x,y;
        for(int i=1;i<=n-1;i++)
        {
            x=p[i].id;
            y=p[i+1].id;
            int u=max(x,y);
            int v=min(x,y);
            if(f(v,u))
                G[v].push_back(node(u,d));
        }
        for(int i=2;i<=n;i++)
        {
            if(f(i,i-1))
                G[i].push_back(node(i-1,-1));
        }
        int s=min(p[n].id,p[1].id);//!!!高的房子不一定編號大,低的房子不一定編號小,因為x[i]-x[j]<=x,要求i>j 請注意
        int e=max(p[n].id,p[1].id);
        int flag=spfa(s,n);
        printf("Case %d: ",ca++);
        if(flag==0)
        {
            printf("-1\n");
        }else
        {
            printf("%lld\n",dis[e]);
        }
    }
    return 0;
}

/*
題目意思:
n個房子,線性一維排列,房子有高度,房子不能在同一個位置,現在有一個超人,從最低的房子開始跳,
每次跳的房子的高度要求比上一個房子的高度高,每個房子都要跳,最後要停在最高的房子上
你可以隨意改變任意房子之間的距離,但是不能改變房子的相對位置
每次超人最多跳D遠,問你超人跳完之後
最低的房子和最高的房子之間的距離最大可以是多少?

分析:
每次要求跳的高度遞增且要是最高的房子結束
說明跳的房子的順序已經排列好了
給線性一維上的房子編個號,1到n
按照高度升序排序,得到的編號順序就是跳的順序

假設x[i]:表示房子i的位置
x[i]-x[j]表示房子i和j之間的距離,i>j
比如樣例1
高度:20 30 10 40
編號:1  2  3  4
按照高度升序排序之後,跳的順序為:3 1 2 4
對每次跳:
x[3]-x[1]<=d
x[2]-x[1]<=d
x[4]-x[2]<=d
注意每次都是編號大的房子位置減去編號小的房子位置,這樣才能得到兩者間的距離

隱藏關係:同一個位置不能有兩個房子
則:x[i]-x[i-1]>=1,i屬於2到n
變形一下:x[i-1]-x[i]<=-1
現在所有的約束關係是都是這個形式:x[i]-x[j]<=x
開始建圖,j->i 權值為x
比如上面的樣例:
1->3 權值4
11->2 權值4
2->4 權值4
2->1 權值-1
3->2 權值-1
題目要求是從最低的房子到最高的房子的最大距離
注意:是最高房子和最低房子中編號小的房子出發,做起點
最高房子和最低房子中編號大的房子結束,做終點
因為高的房子編號不一定大,低的房子編號不一定小
然後因為表示式是x[i]-x[j]<=x
所以是求最短路,不能使用dj,因為存在負權
推薦使用spfa

*/