1. 程式人生 > >2018.12.1 萬聖節的小L

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;
  
  }
  
  複製程式碼
  
  /*====年輕人,瞎搞是出不了省一的,這就是現實====*/