链接:点击打开链接
题意:在x轴上有n个房子,现在要求从高度最小的房子递增跳完所有的房子,每次水平跳跃距离小于m,可以移动每个房子的横坐标,但不能改变原始的位置关系,问最低的房子和最高的房子横坐标差的绝对值最大是多少
代码:
#include <stack>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int n,k,dis[1005],cnt[1005],head[1005];
bool vis[1005];
struct edge{
int to,w,next;
}G[1005*1005/2];
void addedge(int u,int v,int w){
G[k].to=v,G[k].w=w,G[k].next=head[u],head[u]=k++;
}
int spfa(int st,int en){
int i,t;
stack<int>que;
memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
que.push(st);dis[st]=0;
while(!que.empty()){
t=que.top();que.pop();
vis[t]=0;
for(i=head[t];i!=-1;i=G[i].next){
if(dis[t]+G[i].w<dis[G[i].to]){
dis[G[i].to]=dis[t]+G[i].w;
if(!vis[G[i].to]){
vis[G[i].to]=1;
que.push(G[i].to);
if(++cnt[G[i].to]>n)
return -1;
}
}
}
}
if(dis[en]==INF)
return -1;
return dis[en];
}
int a[1005],b[1005],pre[1000005],sign[1000005]; //最短路去查分约束最大值
int main(){ //dis[i+1]>=dis[i]+1,所以i+1->i连条-1的边
int i,j,m,t,ans,cas; //但要注意先后顺序,因此需要记住排序前后的位置
scanf("%d",&t);
for(cas=1;cas<=t;cas++){
scanf("%d%d",&n,&m);
k=0;
memset(pre,0,sizeof(pre));
memset(sign,0,sizeof(sign));
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
pre[a[i]]=i;
b[i]=a[i];
}
sort(a+1,a+n+1);
for(i=1;i<=n;i++)
sign[a[i]]=i;
for(i=2;i<=n;i++){ //判断当前点的位置是在前还是在后
if(pre[a[i]]>pre[a[i-1]])
addedge(i-1,i,m);
else
addedge(i,i-1,m);
}
for(i=2;i<=n;i++){
if(pre[b[i]]>pre[b[i-1]])
addedge(sign[b[i]],sign[b[i-1]],-1);
else
addedge(sign[b[i-1]],sign[b[i]],-1);
}
if(pre[a[1]]<pre[a[n]]) //看起点终点的位置
ans=spfa(1,n);
else
ans=spfa(n,1);
printf("Case %d: %d\n",cas,ans);
}
return 0;
}