【NOIP2014提高组T3】飞扬的小鸟-完全背包

(本人本题完成于2016-7-23)

题目:飞扬的小鸟-题目

做法:可以看出,这道题目类似于完全背包问题,可以用动态规划解决。用f[i][j]表示到达坐标(i,j)时最小的点击次数。注意处理顶部的情况。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define inf 99999999
using namespace std;
int n,m,k,passed=0,in[20010]={0},de[20010]={0}; //in[i],de[i]:在横坐标为i的位置的点击一次的上升高度和不点击的下降高度
int f[2][2010]={0}; //滚动数组
int bot[20010]={0},top[20010]={0}; //bot[i],top[i]:横坐标为i的管道缝隙的下沿高度和上沿高度
int now,past;

int main()
{
  scanf("%d %d %d",&n,&m,&k);
  for(int i=0;i<=n-1;i++)
    scanf("%d %d",&in[i],&de[i]);
  for(int i=0;i<=n;i++)
    top[i]=m+1;
  for(int i=1;i<=k;i++)
  {
    int x;
    scanf("%d",&x);
	scanf("%d %d",&bot[x],&top[x]);
  }
  
  now=1;past=0;
  for(int i=1;i<=n;i++)
  {
    for(int j=0;j<=m;j++)
	  f[now][j]=inf;
    for(int j=1;j<=m;j++)
	  if (j-in[i-1]>0) f[now][j]=min(f[now][j],min(f[past][j-in[i-1]]+1,f[now][j-in[i-1]]+1));
    for(int j=m-in[i-1];j<=m;j++)
	  f[now][m]=min(f[now][m],min(f[past][j]+1,f[now][j]+1)); //处理顶部情况
	for(int j=m;j>=1;j--)
	  if (j+de[i-1]<=m) f[now][j]=min(f[now][j],f[past][j+de[i-1]]);
	for(int j=0;j<=bot[i];j++) f[now][j]=inf;
	for(int j=top[i];j<=m;j++) f[now][j]=inf;
	if (top[i]<=m)
	  for(int j=1;j<=m;j++) if (f[now][j]!=inf) {passed++;break;} //如果当前位置有管道缝隙并通过了,统计
    int t=now;now=past,past=t;
  }
  
  int ans=inf;
  for(int i=1;i<=m;i++) ans=min(ans,f[past][i]);
  if (passed<k) printf("0\n%d",passed);
  else printf("1\n%d",ans);
  
  return 0;
}


posted @ 2016-07-23 18:33  Maxwei_wzj  阅读(94)  评论(0编辑  收藏  举报