1. 程式人生 > >2018年6月8號(過河)

2018年6月8號(過河)

++ col c++ 所有 容易 thml pan 大於 暴力

題目描述

在河上有一座獨木橋,一只青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點: 0,1,…,L0,1,,L (其中 LL 是橋的長度)。坐標為 00 的點表示橋的起點,坐標為 LL 的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是 SS 到 TT 之間的任意正整數(包括 S,TS,T )。當青蛙跳到或跳過坐標為 LL 的點時,就算青蛙已經跳出了獨木橋。

題目給出獨木橋的長度 LL ,青蛙跳躍的距離範圍 S,TS,T ,橋上石子的位置。你的任務是確定青蛙要想過河,最少需要踩到的石子數。

輸入輸出格式

輸入格式:

第一行有 11 個正整數 L(1 \le L \le 10^9)L(1L109) ,表示獨木橋的長度。

第二行有 33 個正整數 S,T,MS,T,M ,分別表示青蛙一次跳躍的最小距離,最大距離及橋上石子的個數,其中 1 \le S \le T \le 101ST10 , 1 \le M \le 1001M100 。

第三行有 MM 個不同的正整數分別表示這 MM 個石子在數軸上的位置(數據保證橋的起點和終點處沒有石子)。所有相鄰的整數之間用一個空格隔開。

輸出格式:

一個整數,表示青蛙過河最少需要踩到的石子數。

輸入輸出樣例

輸入樣例#1: 復制
10
2 3 5
2 3 5 6 7
輸出樣例#1: 復制
2

說明

對於30%的數據, L \le 10000L10000 ;

對於全部的數據, L \le 10^9L109 。

2005提高組第二題

-----------------------------------------------------------------------

一開始那道這道題,我就開始進行暴力枚舉從後往前做,只要找到第一個符合條件的就往那跳,結果wa 0分;

麽有辦法,就看了大佬們怎麽做:

大佬做法:

我們用 f[i]表示在數軸的 i 點時所能踩石子的最少個數

那麽很容易得出狀態轉移方程:
if(i點有石子) f[i]=min(f[i],f[i-j]+1)
else f[i]=min(f[i],f[i-j])
然而數軸長到fai起,那麽我們就壓縮一下
先把石子位置(用數組a來存放)從小到大排序,計算兩兩石子間的距離(用數組d來存放),如果距離<=t,那麽a[i]=a[i-1]+d[i]
如果距離大於t,那麽就需要壓縮距離了,即 a[i]=a[i-1]+t+(d[i]%t)
然後還有要註意的兩點
1.它的石子沒說是已經排好序的,我看了樣例以為都是排好序的,RE了一遍。
2.註意取p的範圍,就是要在壓縮的路程後面加一個t,因為不一定最後一個點剛好是石頭最少的,可能是p+1,p+2,所以要從它轉移過來

最後附上代碼:

 1 #include<bits/stdc++.h>  
 2 #define ll long long  
 3 using namespace std;  
 4 int f[20000],vis[20000],a[211],b[211];  
 5 int main()  
 6 {  
 7     ll l;
 8     int s,t,m;
 9     cin>>l;
10     cin>>s>>t>>m;
11     memset(f,0x3f,sizeof(f));
12     memset(vis,0,sizeof(vis));
13     a[0]=0;
14     for(int i=1;i<=m;i++)
15         cin>>a[i];
16     a[m+1]=l;
17     sort(a,a+m+2);
18     b[0]=0;
19     int cnt=0;
20     for(int i=1;i<=m+1;i++)  
21     {
22            if(a[i]-a[i-1]>=t)
23         cnt+=(a[i]-a[i-1])%t+t;
24            else
25            cnt+=a[i]-a[i-1];
26            vis[cnt]=1;
27     }
28     vis[cnt]=0;
29     vis[0]=0;
30     f[0]=0;  
31     for(int i=1;i<=cnt+t-1;i++)  
32     {  
33            for(int j=s;j<=t;j++)  
34         if(i-j>=0)
35         f[i]=min(f[i],f[i-j]+vis[i]);  
36     }
37     int ans=2100000000;
38     for(int i=cnt;i<=cnt+t-1;i++)
39     ans=min(f[i],ans);
40     cout<<ans;
41     return 0;
42 }

2018年6月8號(過河)