2018.11.06【NOIP2014】【洛谷P1941】飞扬的小鸟(背包问题)

传送门


解析:

知道是背包后应该比较好像,但是这道题最难的应该就是看出这是一道背包问题。。。

思路;

考虑用 f [ i ] [ j ] f[i][j] f[i][j],表示让小鸟达到位置 ( i , j ) (i,j) (i,j)需要的最小点击次数, I N F INF INF表示无法到达。

然后初始化十分显然 f [ 0 ] [ j ] = 0 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值