[提高] 飞扬的小鸟[组合背包]
飞扬的小鸟
const int maxn=10010;
const int maxm=2010;
int n,m,p;
int x[maxn],y[maxn];//当前位置上升的位置和下降的距离
int low[maxn],high[maxn];//当前位置的上下限制边界
int f[maxn][maxm];//动态规划的转移方程
bool e[maxn];//当前位置有没有经过管道
void solve(){
//try it again.
cin>>n>>m>>p;
up(1,n)cin>>x[o]>>y[o];//输入上升和下降的位置
up(1,n){
low[o]=1;//最低不能到地板
high[o]=m;//最高不能到天花板
}
int a,b,c;
up(1,p){
cin>>a>>b>>c;
e[a]=true;//当前位置有管道
low[a]=++b;//地板上面一个
high[a]=--c;//天花板下面一个
}
mem(f);//未转移到的状态
up(1,m)f[0][o]=0;//初始化出发的位置
fup(i,1,n){//按x的位置遍历.类似于背包的转移
fup(j,x[i]+1,m+x[i]){//上升一次和无限制上升
f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
}
fup(j,m+1,m+x[i]){//到达天花板上面的归并到天花板
f[i][m]=min(f[i][m],f[i][j]);
}
fup(j,1,m-y[i]){//自然下降
f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
}
fup(j,1,low[i]-1){//不合法的状态设置为无法达到
f[i][j]=f[0][0];
}
fup(j,high[i]+1,m){//不合法的状态设置为无法达到
f[i][j]=f[0][0];
}
}
int ans=f[0][0];
up(1,m){
ans=min(ans,f[n][o]);
}
if(ans<f[0][0]){//可以到达最后一列
cout<<1<<endl;
cout<<ans<<endl;
}
else{//无法到达
cout<<0<<endl;
int i,j;
for(i=n;i>=1;i--){//往回扫经过的管道数
for(j=1;j<=m;j++){
if(f[i][j]<f[0][0])break;
}
if(j<=m)break;
}
ans=0;
fup(j,1,i)if(e[j])ans++;
cout<<ans<<endl;
}
}