【USACO2006 Mar】滑雪缆车 skilift
【USACO2006 Mar】 滑雪纜車 skilift
Time Limit 1000 ms
Memory Limit 131072 KBytes
Description
科羅拉多州的羅恩打算為奶牛建造一個滑雪場,為此要在山上規劃一條纜車線路。
整座山可以用一條折線來描述,該折線有N個拐點,起點是1,終點是N。每個拐點的高度為Hi,相鄰兩個拐點之間的水平距離都是1。
纜車線路必須從起點開始修建,結束于終點。中間可以選擇一些拐點安放纜繩的支柱,安全標準有兩點:第一,纜繩的跨度有限制——相鄰支柱的水平距離不能超過K;第二,纜繩的高度有限制——兩根支柱之間的鋼絲視作筆直的,在這座山的任何位置,鋼絲都不能低于山的高度,但允許纜繩緊貼在山坡上或恰好穿過某個山峰。支柱相對于拐點的高度不計。
為了節約,羅恩希望修建的支柱越少越好,請幫他規劃一下吧!當然,起點和終點上是一定要修建支柱的。
Input
第一行:兩個用空格分開的整數:N和K,2 ≤ N ≤ 5000,1 ≤ K ≤ N ? 1
第二行到N + 1行:第i + 1行有一個整數Hi,0 ≤ Hi ≤ ${10^9}$
Output
第一行:單個整數,表示最少需要修建的支柱數量
Sample Input
13 4
0
1
0
2
4
6
8
6
8
8
9
11
12
Sample Output
5
Hint
樣例解釋:支柱設在 1、5、7、9、13 號點處是最優方案。如果只設在 1、5、9、13 上,那么5 到9 就會有鋼絲低于山坡的高度。如果只在 1、7、13 上修建,雖然高度符合要求,但這兩段支柱的水平距離都超過了K。
?
Solution
身為菜雞,打算再寫一道dp
?
這道題的狀態還是較容易設計的,即f[i]表示到第i個拐點所需設置的最少支柱數
?
那么一看數據范圍,2000!!!!!!!!!!!
?
這就可以放心地亂搞寫轉移方程了
?
只要在前面的拐點中找到水平距離小于等于k且在這兩個拐點之間所有拐點都不會插♂斷這條纜繩的拐點,在這些拐點中求min(f[j])再加上改點即可
?
然后掛方程:$f[i] = \min \left\{ {\left. {f[j]} \right\}} \right. + 1,{\rm{1}} < = j < = i - 1$且j滿足以上條件
?
那么我們現在就只剩下最后一個問題,如何判斷纜繩不會被插♂斷呢?
?
我們可以先做一個預處理,以(0,0)為坐標原點,把每個拐點寫成一個點,顯然,如果兩個點之間沒有點可以把纜繩插♂斷,那么這兩個點的所在的直線的斜率一定比前面那個點到兩點之間每個點的斜率都要大
?
我們只需要用一個bool數組$b\left[ i \right]\left[ j \right]$來記錄下第i個拐點是否能夠達到第j個拐點
?
這樣就能完美解決這道題了OwO
?
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; bool b[5005][5005]; int f[5005],a[5005]; double x=1e-6; bool check(double a,double b){return abs(a-b)<=x;} int main() {int n,k;scanf("%d%d",&n,&k);for (int i=1;i<=n;i++) scanf("%d",&a[i]);for (int i=1;i<=n;i++){double lim=-2147483640.0;for (int j=i+1;j<=n;j++) {if (check(lim,1.0*(a[j]-a[i])/(j-i))||lim<=1.0*(a[j]-a[i])/(j-i)) b[i][j]=true;lim=max(lim,1.0*(a[j]-a[i])/(j-i));} }f[1]=1;for (int i=2;i<=n;i++){f[i]=2147483640;for (int j=1;j<=i-1;j++) if (b[j][i]&&i-j<=k) f[i]=min(f[i],f[j]+1);}printf("%d",f[n]);return 0; }?
轉載于:https://www.cnblogs.com/Cool-Angel/p/7728287.html
總結
以上是生活随笔為你收集整理的【USACO2006 Mar】滑雪缆车 skilift的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VisualVM介绍使用
- 下一篇: 软工Hello World!团队第二周博