題意:給出一組房子,房子有高度,並且只能從低房子跳到相應稍微高的房子,跳的長度還有限制,然後房子可以移動,但是序列不能動,沒有兩個房子處於同一個位置,現在問最高的房子位置在哪.
題解:首先根據房子不在同一位置可以得出s[i+1]-s[i]>=1,然後又根據跳的限制,把高度排好序後,之後還得處理下序號,都是小事,然後s[v]-s[u]<=u,之後還是都轉換成<=號,然後就可以導出答案了。
感悟:這個題得到的感悟比較多,第一次我是用都轉換成>=號做的,確實能做,進隊我還用的超級源點,之後發現根本不對,用>=號就得倒着來,用<=號就是正着,用<=號就不用亂倒,很好,最後發現只要說求那兩個點啥的,都用<=號比較好,輸出答案之類用啥都行,儘量再畫個圖驗證一番最好了。也是稍微感覺有點摸到了差分約束的本質,只要條件能找全,然後邊緣處理好,入隊方式處理處理,就沒問題了。
附上代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1100;
const int maxm=maxn*maxn*2;
const int inf=0x7fffffff;
struct edge{
int v,w,next;
};
edge edges[maxm];
int head[maxn],tot;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void add_edges(int u,int v,int w)
{
edges[tot].v=v;
edges[tot].w=w;
edges[tot].next=head[u];
head[u]=tot++;
}
struct house{
int hight,no;
};
house arr[maxn];
bool cmp(house a,house b)
{
return a.hight<b.hight;
}
int n,d;
int dist[maxn],cnt[maxn];
bool vis[maxn];
int spfa(int s,int t)
{
queue<int>q;
for(int i=1;i<=n;i++){
cnt[i]=0;dist[i]=inf;vis[i]=false;
}
q.push(s);
dist[s]=0;vis[s]=true;
while(!q.empty()){
int u=q.front();
q.pop();
if(++cnt[u]>n){
return -1;
}
vis[u]=false;
for(int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].v,w=edges[i].w;
if(dist[v]>dist[u]+w){
dist[v]=dist[u]+w;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
return dist[t];
}
int main()
{
int T,casen=1;
scanf("%d",&T);
while(T--){
init();
scanf("%d%d",&n,&d);
for(int i=1;i<=n;i++){
scanf("%d",&arr[i].hight);
arr[i].no=i;
if(i!=n){
add_edges(i+1,i,-1);
}
}
sort(arr+1,arr+n+1,cmp);
for(int i=1;i<n;i++){
int u=arr[i].no,v=arr[i+1].no;
if(u>v){
swap(u,v);
}
add_edges(u,v,d);
}
int u=arr[1].no,v=arr[n].no;
if(u>v){
swap(u,v);
}
printf("Case %d: %d\n",casen++,spfa(u,v));
}
return 0;
}