【动态规划】P1941 飞扬的小鸟

用f[i][j]表示小鸟从开始到(i,j)的位置最小点击次数,具体转移方程见代码

注意:要判断是否超过上边界

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
const int maxm=2005;
int n,m,p;
int up[maxn],down[maxn],low[maxn],high[maxn];
int f[maxn][maxm];
int pipe[maxn];
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;i++) scanf("%d%d",&up[i],&down[i]);
	for(int i=1;i<=n;i++) low[i]=1,high[i]=m; 
	int x,y,z;
	for(int i=1;i<=p;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		pipe[x]=1;
		low[x]=y+1;
		high[x]=z-1;
	}
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=m;i++) f[0][i]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=up[i]+1;j<=m+up[i];j++)
			f[i][j]=min(f[i][j],min(f[i-1][j-up[i]]+1,f[i][j-up[i]]+1));//当前位置是上一次上升或者这次上升得来的
		for(int j=m+1;j<=m+up[i];j++)
			f[i][m]=min(f[i][m],f[i][j]); //处理超过上边界的部分
		for(int j=1;j<=m-down[i];j++)
			f[i][j]=min(f[i][j],f[i-1][j+down[i]]); //当前状态可能是上一次下降得到的
		for(int j=1;j<low[i];j++) f[i][j]=f[0][0];
		for(int j=high[i]+1;j<=m;j++) f[i][j]=f[0][0]; 
	}
	int ans=f[0][0];
	for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
	if(ans!=f[0][0]) printf("1\n%d\n",ans);
	else
	{
		int pos=0; ans=0;
		for(int i=n;i>=1,!pos;i--)
			for(int j=1;j<=m;j++)
				if(f[i][j]<f[0][0]) {pos=i; break;}
		for(int j=1;j<=pos;j++)
			if(pipe[j]) ans++;
		printf("0\n%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/andyc_03/article/details/107635932
今日推荐