2018.12.1 萬聖節的小L
試題描述
今天是萬聖節,小L同學開始了一年一度的討要糖果遊戲,但是在剛剛過去的比賽中小有成就的他打算給自己增加一點難度:如果沒有討到每一家的糖果就算輸。
已知小L共有n(n不大於10000)個鄰居,他們都在同一條街上(可以近似看成一條直線),第i個鄰居的座標是xi。L同學的媽媽會在一開始把他送到任意鄰居的門前。現在已知所有鄰居會在di時間後休息(休息以後不能再去打擾),求訪問完所有點的最短時間,如果無解輸出“No solution”。
輸入
輸入第一行為一個正整數表示n,接下來n行,每行兩個用空格隔開的數,分別表示第i個鄰居的位置和休息時間。
輸出
輸出一個數,表示最短時間,無解輸出“No solution”。
輸入示例
5
1 3
3 1
5 8
8 19
10 15
輸出示例
11
看起來是一個搜尋或者dp
然鵝發現搜尋會TLE
考慮dp:
為了轉移我們儲存的資料我們不能採用普通的區間dp
我們不難發現,為了遍歷直線上的每一個點,其中一個端點一定是最後經過的點(自己可以推一下)
所以我們用dp[i][j][0]表示從i到j結束在左端點的最短時間
用dp[i][j][1]表示從i到j結束在右端點的最短時間
於是對於i到j+1的區間在合法範圍內就有了兩種選擇:從i到j區間轉移或者從i-1到j+1區間轉移
但是發現空間開不下於是我們換一種儲存方式
為了節省空間我們只儲存區間起點(壓縮一維儲存區間長度奇數偶數)
於是我們又有了四種轉移方式:
對於從i到j的區間,從i-1到j轉移(兩種)或者從i到j-1轉移(兩種)
關於轉移:
對於區間dp來講,無後效性體現在從一步到下一步的轉移
所以轉移的代價是從結束時間到下一個節點的距離
關於合法:主要就是時間不要超過
上程式碼
複製程式碼
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
int n,dp[2][20010][2],xx[10005],d[10005],nx;
int main()
{
scanf("%d",&n);
for(int i=1;i<www.tianjiuyule178.com=n;i++)scanf("%d%d",&xx[i],&d[i]);
for(int i=1;i<=n;i++)dp[0][i][0]=dp[0][i][1]=0;
for(int i=1;i<www.haom178.com n;i++)
{
int x=nx;nx^=1;
for(int j=1;j<=n-i;j++)
{
dp[nx][j][0]=min(dp[x][j+1][0]+xx[j+1]-xx[j],dp[x][j+1][1]+xx[j+i]-xx[j]);
dp[nx][j][1]=min(dp[x][j][0]+xx[j+i]-xx[j],dp[x][j][1]+xx[j+i]-xx[j+i-1]);
if(dp[nx][j][0]>d[j])dp[nx][j][0]=INF;
if(dp[nx][j][1]>d[i+j])dp[nx][j][1]=INF;
}
}
int ans=min(dp[nx][www.michenggw.com][0],dp[nx][1][1]);
if(ans>=INF)puts("No www.mhylpt.com solution");
else printf("%d",ans);
return 0;
}
複製程式碼
/*====年輕人,瞎搞是出不了省一的,這就是現實====*/