洛谷 P1941 飞扬的小鸟 (NOIP 2014)
题解
背包细节题,wa了一片,上升的过程我们可以看做一个完全背包(多重背包好像跑不过去),下降
过程是一个0/1背包,为了避免冲突应该先跑多重,先跑0/1就有可能产生这个点又上升又下降的
非法情况,最后在将非法情况删去。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXM = 1005;
const int MAXN = 10005;
const int inf = 0x3f3f3f3f;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int dp[MAXN][MAXM],px[MAXN],py[MAXN];
int n,m,k,ans=inf;
int x[MAXN],y[MAXN];
int main(){
memset(dp,0x3f,sizeof(dp));
n=rd();m=rd();k=rd();
for(register int i=1;i<=n;i++) x[i]=rd(),y[i]=rd(),py[i]=inf;
for(register int i=1;i<=k;i++) {
int where;where=rd();
px[where]=rd();py[where]=rd();
}
for(register int i=1;i<=m;i++) dp[0][i]=0;
for(register int i=1;i<=n;i++){
for(register int j=x[i];j<=m;j++){
if(j==m)
for(register int o=m-x[i];o<=m;o++){
dp[i][j]=min(dp[i][j],dp[i-1][o]+1);
dp[i][j]=min(dp[i][j],dp[i][o]+1);
}
dp[i][j]=min(dp[i][j],dp[i-1][j-x[i]]+1);
dp[i][j]=min(dp[i][j],dp[i][j-x[i]]+1);
}
int l=max(px[i]+1,1);int r=min(py[i]-1,m-y[i]);
for(register int j=l;j<=r;j++)
dp[i][j]=min(dp[i][j],dp[i-1][j+y[i]]);
for(register int j=px[i];j;j--) dp[i][j]=inf;
for(register int j=py[i];j<=m;j++) dp[i][j]=inf;
}
// for(register int i=1;i<=n;i++){
// cout<<i;
// for(register int j=1;j<=m;j++)
// cout<<" "<<j<<" "<<dp[i][j]<<endl;
// cout<<endl;
// }
for(register int i=1;i<=m;i++) ans=min(dp[n][i],ans);
if(ans!=inf){
puts("1");
printf("%d",ans);
}
else{
ans=0;
puts("0");
for(register int i=1;i<=n;i++){
bool flag=false;
for(register int j=1;j<=m;j++)
if(dp[i][j]!=inf){
flag=1;
if(py[i]!=inf){
ans++;
break;
}
}
if(!flag) break;
}
printf("%d",ans);
}
return 0;
}