洛谷P1941 飞扬的小鸟

好不容易写了这么长的注释当然要扔博客里……

学DP的第一天,想哭。

注意:由于愤怒的小鸟跳跃最大高度理论上是m最大值+x最大值,故f的第二维要开到两千以上。

 1 #include<bits/stdc++.h>
 2 #define ff(i,s,e) for(int i=s;i<=e;i++)
 3 #define fff(i,s,e) for(int i=s;i>=e;i--)
 4 using namespace std;
 5 inline int read(){
 6     register int x=0,f=1;register char ch=getchar();
 7     while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
 8     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 9     return x*f;
10 }
11 const int N=1e4+5,M=1e3+5;
12 int n,m,k;
13 int x[N],y[N];
14 int low[N],high[N];
15 bool vis[N];
16 int f[N][2*M];//(i,j)最小次数
17 int main(){
18     n=read(),m=read(),k=read();
19     ff(i,1,n){
20         x[i]=read(),y[i]=read();
21         high[i]=m;low[i]=1;
22     }
23     int p,l,h;
24     ff(i,1,k){
25         p=read();l=read();h=read();
26         vis[p]=1;
27         low[p]=l+1,high[p]=h-1;
28     }
29     memset(f,0x3f,sizeof(f));//为取min做准备 
30     ff(i,1,m) f[0][i]=0;//使i等于1算出正确答案 
31     ff(i,1,n){
32         ff(j,x[i]+1,m+x[i])//往上跳之后高度范围 
33             f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);//上一秒往上跳和这一秒连跳结果取最小 
34         ff(j,m+1,m+x[i])//跳冒了 ,最后纵坐标一定为m 
35             f[i][m]=min(f[i][m],f[i][j]);//找最小方案 
36         ff(j,1,m-y[i])//往下掉之后高度范围 
37             f[i][j]=min(f[i][j],f[i-1][j+y[i]]);//和之前往上跳到当前位置(跳不到就是0x3f)得出的最优方案比取最小 
38         ff(j,1,low[i]-1) f[i][j]=f[0][0];
39         ff(j,high[i]+1,m) f[i][j]=f[0][0];
40         //一定跳不到的地方赋统一值
41     }
42     int ans=f[0][0];
43     ff(j,1,m){
44         ans=min(ans,f[n][j]);//到达终点时枚举每个高度找最小的方案 
45     }
46     if(ans<f[0][0]){printf("1\n%d",ans);return 0;}//若有最小方案 
47     int i,j;
48     for(i=n;i>=1;i--){//从后往前搜索愤怒的小鸟能跳到的地方 
49         for(j=1;j<=m;j++)
50                 if(f[i][j]<f[0][0]){break;}//根据前面dp,若愤怒的小鸟跳不到则f[i][j]仍为0x3f 
51         if(j<=m) break;//若第i列所有高度愤怒的小鸟都过不去,则此时的i就是鸟到达的最远处 
52     }
53     ans=0;
54     for(int j=1;j<=i;j++) if(vis[j]) ans++;
55     return printf("0\n%d",ans),0;
56 } 

 

posted @ 2022-02-09 23:43  专吃小仙女  阅读(50)  评论(0)    收藏  举报