P1941 飞扬的小鸟(背包)

P1941 飞扬的小鸟

细节题

上升是完全背包

下降是01背包

(数组访问越界本机怎么能过???(大雾))

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cctype>
 5 #define re register
 6 using namespace std;
 7 void read(int &x){
 8     char c=getchar();x=0;
 9     while(!isdigit(c)) c=getchar();
10     while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
11 }
12 int min(int &a,int &b){return a<b?a:b;}
13 int max(int &a,int &b){return a>b?a:b;}
14 void swap(int &a,int &b){a^=b;b^=a;a^=b;}
15 #define N 10002
16 int ans=2e9,n,m,k,f[N][2002];
17 int a[N],b[N],l[N],r[N],v[N];
18 int main(){
19     read(n); read(m); read(k); int q1,q2,q3;
20     for(re int i=1;i<=n;++i){
21         read(a[i]); read(b[i]);
22         l[i]=1; r[i]=m;//下/上界
23     }
24     for(re int i=1;i<=k;++i){
25         read(q1); read(q2); read(q3);
26         if(q2>q3) swap(q2,q3);
27         l[q1]=q2+1; r[q1]=q3-1; v[q1]=1;//v:当前列是否有管子
28     }
29     memset(f,63,sizeof(f)); int inf=f[0][0],tot=0;
30     for(re int i=1;i<=m;++i) f[0][i]=0;
31     for(re int i=1;i<=n;++i){
32         for(re int j=a[i]+1;j<=m+a[i];++j) //上升完全背包
33             f[i][j]=min(f[i][j-a[i]],f[i-1][j-a[i]])+1;
34         for(re int j=m+1;j<=m+a[i];++j) //飞到m时特判
35             f[i][m]=min(f[i][m],f[i][j]);
36         for(re int j=1;j<=m-b[i];++j)//下降01背包
37             f[i][j]=min(f[i][j],f[i-1][j+b[i]]);
38         for(re int j=1;j<l[i];++j) f[i][j]=inf;//其他地方不能飞
39         for(re int j=r[i]+1;j<=m;++j) f[i][j]=inf;
40         bool gg=1;
41         for(re int j=l[i];j<=r[i];++j) gg=(gg&&f[i][j]>=inf);
42         if(gg){printf("0\n%d",tot); return 0;}//无法飞下去
43         tot+=v[i];
44     }
45     for(re int i=l[n];i<=r[n];++i) ans=min(ans,f[n][i]);
46     printf("1\n%d",ans);
47     return 0;
48 } 
View Code

 

posted @ 2018-10-19 12:00  kafuuchino  阅读(140)  评论(0编辑  收藏  举报