1. 程式人生 > >2018.11.06【NOIP2014】【洛谷P1941】飛揚的小鳥(揹包問題)

2018.11.06【NOIP2014】【洛谷P1941】飛揚的小鳥(揹包問題)

傳送門


解析:

知道是揹包後應該比較好像,但是這道題最難的應該就是看出這是一道揹包問題。。。

思路;

考慮用 f [ i ] [ j ]

f[i][j] ,表示讓小鳥達到位置 ( i , j ) (i,j) 需要的最小點選次數, I
N F INF
表示無法到達。

然後初始化十分顯然 f [ 0 ] [ j

] = 0 f[0][j]=0

接下來就是揹包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;
}