NOIp提高組2014 飛揚的小鳥————dp+揹包綜合

題解:本題主要考查揹包綜合。
簡要題意:一個長爲nn,高爲mm的二維平面,其中有kk個管道。小鳥每個單位時間向右移的距離爲11,在橫座標位置0n0∼n點擊屏幕,小鳥就會上升高度XiX_i,每個單位時間可以點擊多次。如果在橫座標位置0n0∼n不點擊屏幕,小鳥就會下降一定高度YiY_i,小鳥高度等於00或者小鳥碰到管道時失敗,小鳥高度爲mm時,無法再上升。
1.dp:用f[i][j]f[i][j]表示橫座標爲ii時高度爲jj的最少點擊次數。
上升時:由前一個單位時間內的jXij-X_i​跳了一次得來的或由現在的jXij-X_i​跳了一次得來的:
f[i][j]=min(f[i][jx[i]]+1,f[i1][jx[i]]+1);f[i][j]=min(f[i][j-x[i]]+1,f[i-1][j-x[i]]+1);
下降時:由前一個單位時間內j+Yij+Y_i下降而來的,所以
f[i][j]=min(f[i][j],f[i1][j+y[i]]);f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
如果是在頂層就只要將向上跳時溢出mm高度與自己比較即可。
2.注意事項:循環高度時,應該爲j<=m+Xij<=m+X_i,判斷卡在頂部的情況,因爲如果只是j<=mj<=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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章