NOIp提高组2014 飞扬的小鸟————dp+背包综合

题解:本题主要考查背包综合。
简要题意:一个长为 n n n,高为 m m m的二维平面,其中有 k k k个管道。小鸟每个单位时间向右移的距离为 1 1 1,在横坐标位置 0 ∼ n 0∼n 0n点击屏幕,小鸟就会上升高度 X i X_i Xi,每个单位时间可以点击多次。如果在横坐标位置 0 ∼ n 0∼n 0n不点击屏幕,小鸟就会下降一定高度 Y i Y_i Yi,小鸟高度等于 0 0 0或者小鸟碰到管道时失败,小鸟高度为 m m m时,无法再上升。
1.dp:用 f [ i ] [ j ] f[i][j] f[i][j]表示横坐标为 i i i时高度为 j j j的最少点击次数。
上升时:由前一个单位时间内的 j − X i j-X_i jXi​跳了一次得来的或由现在的 j − X i j-X_i jXi​跳了一次得来的:
f [ i ] [ j ] = m i n ( f [ i ] [ j − x [ i ] ] + 1 , f [ i − 1 ] [ j − x [ i ] ] + 1 ) ; f[i][j]=min(f[i][j-x[i]]+1,f[i-1][j-x[i]]+1); f[i][j]=min(f[i][jx[i]]+1,f[i1][jx[i]]+1);
下降时:由前一个单位时间内 j + Y i j+Y_i j+Yi下降而来的,所以
f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i − 1 ] [ j + y [ i ] ] ) ; f[i][j]=min(f[i][j],f[i-1][j+y[i]]); f[i][j]=min(f[i][j],f[i1][j+y[i]]);
如果是在顶层就只要将向上跳时溢出 m m m高度与自己比较即可。
2.注意事项:循环高度时,应该为 j < = m + X i j<=m+X_i j<=m+Xi,判断卡在顶部的情况,因为如果只是 j < = m j<=m j<=m就很有可能把这种情况忽略。
数组要开大一点
代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int f[11000][2666],x[20000],y[20000];
int guanl[20000],guanh[20000],vis[20000];
int n,m,k,ans=0x3f3f3f3f,sum;
int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	cin>>x[i]>>y[i];
	for(int i=1;i<=n;i++){guanl[i]=1;guanh[i]=m;}
	for(int i=1;i<=k;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		vis[a]=1;
		guanl[a]=b+1;guanh[a]=c-1;
	}
	memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=1;i<=m;i++)f[0][i]=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=x[i]+1;j<=m+x[i];j++)
	    f[i][j]=min(f[i][j-x[i]]+1,f[i-1][j-x[i]]+1);
	   
	    for(int j=m+1;j<=m+x[i];j++)
	    f[i][m]=min(f[i][m],f[i][j]);
	   
	    for(int j=1;j<=m-y[i];j++)
	    f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
	    
		for(int j=1;j<=guanl[i]-1;j++)
	    f[i][j]=0x3f3f3f3f;
	    for(int j=guanh[i]+1;j<=m;j++)
	    f[i][j]=0x3f3f3f3f;
	}
	for(int i=1;i<=m;i++)ans=min(ans,f[n][i]);
	if(ans<0x3f3f3f3f)
	{
		cout<<"1"<<endl<<ans;
		cin>>n;
		return 0;
	}
	int i,j;
    for(i=n;i>=1;i--)//找到没有通过的位置
	{
        for(j=1;j<=m;j++)
        if(f[i][j]<0x3f3f3f)break;
        if(j<=m)break;
    }
    for(j=1;j<=i;j++)
    if(vis[j])sum++;
    cout<<"0"<<endl<<sum;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值