2018.11.06【NOIP2014】【洛谷P1941】飛揚的小鳥(揹包問題)
阿新 • • 發佈:2018-11-10
傳送門
解析:
知道是揹包後應該比較好像,但是這道題最難的應該就是看出這是一道揹包問題。。。
思路;
考慮用 ,表示讓小鳥達到位置 需要的最小點選次數, 表示無法到達。
然後初始化十分顯然 。
接下來就是揹包DP,考慮一個單位時間內可以點選任意次數,所以就是完全揹包,而掉落就是01揹包(但是如果不優化空間,像我一樣,就沒有這些考慮了)。
注意特判上界越界的情況。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=10004,M=2003,INF=0x3f3f3f3f;
int f[N][M];
int low[N],high[N];
bool vis[N];
int x[N],y[N];
int n,m,k;
signed main(){
n=getint();
m=getint();
fill(low+1,low+n+1,1);
fill(high+1,high+n+1,m);
k=getint();
for(int re i=1;i<=n;++i){
x[i]=getint();
y[i]=getint();
}
for(int re i=1;i<=k;++i){
int p=getint(),l=getint(),h=getint();
vis[p]=true;
low[p]=l+1;
high[p]=h-1;
}
memset(f,0x3f,sizeof f);
fill(f[0]+1,f[0]+m+1,0);
for(int re i=1;i<=n;++i){
for(int re j=x[i]+1;j<=m+x[i];++j)f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1);
for(int re j=m+1;j<=m+x[i];++j)f[i][m]=min(f[i][m],f[i][j]);
for(int re j=1;j<=m-y[i];++j)f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
for(int re j=1;j<low[i];++j)f[i][j]=INF;
for(int re j=m;j>high[i];--j)f[i][j]=INF;
}
int ans=INF;
for(int re i=1;i<=m;++i)ans=min(ans,f[n][i]);
if(ans<INF)return cout<<1<<"\n"<<ans<<"\n",0;
ans=0;
int pos;
for(pos=n;pos;--pos){
bool flag=false;
for(int re i=1;i<=m;++i)if(f[pos][i]<INF)flag=true;
if(flag)break;
}
for(int re i=1;i<=pos;++i)if(vis[i])++ans;
cout<<0<<"\n"<<ans<<"\n";
return 0;
}