您的位置:首页 > 其它

HDU - 3440 House Man 【差分约束 + 最短路模型】

2017-09-12 11:32 405 查看
传送门

题意:有n个屋子,超人从最矮的屋子开始,依次跳下比当前屋子高且最接近当前高度的屋子(即按照屋子高度增序来跳),但超人跳跃还有一个水平距离限制D,他每次跳的水平距离<=D。现在给你每个屋子的高度是它们的相对位置,你不能改变屋子的相对位置,但是可以水平移动屋子,使得最矮的屋子和最高的屋子的水平距离最大。如果无论怎样移动,超人都无法跳到最后那个屋子则输出-1

这题是个差束约分

看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的边),所以我们找最短路的时候也要约定从标号小的点 到 标号大的点

AC Code

const int maxn = 1e5+5;
const ll INF = 1e18;
int cas = 1;
int n,d;
struct point
{
int pos,h;
bool operator < (const point& x)const{
return x.h>h;
}
}pot[maxn];

struct node
{
int to,next;
ll w;
}e[maxn];

ll dis[maxn];
int head[maxn],cnt, times[maxn];
bool vis[maxn];
void add(int u,int v,ll w)
{
e[cnt] = (node){v,head[u],w};
head[u] = cnt++;
}
void init() {
cnt = 0 ;
Fill(head , -1);
}
bool spfa(int st,int ed)
{
queue<int >q;
Fill(vis, 0); Fill(times, 0);
for(int i=0;i<=n;i++) dis[i] = INF;
dis[st]=0; vis[st] = true; times[st]++;
q.push(st);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u] ; ~i ; i = e[i].next){
int to = e[i].to;
if(dis[to] > dis[u] + e[i].w){
dis[to] = dis[u] + e[i].w;
if(times[to] > n)
return false;
else if(!vis[to]){
times[to]++;
vis[to] = true;
q.push(to);
}
}
}
}
return true;
}

void solve()
{
scanf("%d%d",&n,&d);
init();
for(int i=1;i<=n;i++){
scanf("%d",&pot[i].h);
pot[i].pos = i;
}
sort(pot+1,pot+n+1);
for(int i=1;i<=n-1;i++){
int x1 = min(pot[i+1].pos,pot[i].pos);
int x2 = max(pot[i+1].pos,pot[i].pos);
add(i+1,i,-1);
add(x1,x2,d);
}
int st = min(pot[1].pos,pot
.pos);
int ed = max(pot[1].pos,pot
.pos);
printf("Case %d: ",cas++);
if(!spfa(st,ed)) printf("-1\n");
else {
if(dis[ed] == INF) printf("-1\n");
else printf("%lld\n",dis[ed]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: