ACM 272. [NOI1998] 免費餡餅(dp)

272. [NOI1998] 免費餡餅

★☆   輸入文件:freepizza.in   輸出文件:freepizza.out   簡單對比
時間限制:1 s   內存限制:128 MB

SERKOI最新推出了一種叫做“免費餡餅”的遊戲:遊戲在一個舞臺上進行。舞臺的寬度爲W格,天幕的高度爲H格,遊戲者佔一格。開始時遊戲者站在舞臺的正中央,手裏拿着一個托盤。下圖爲天幕的高度爲4格時某一個時刻遊戲者接餡餅的情景。

Image:Freepizza.gif

遊戲開始後,從舞臺天幕頂端的格子中不斷出現餡餅並垂直下落。遊戲者左右移動去接餡餅。遊戲者每秒可以向左或向右移動一格或兩格,也可以站在原地不動。

餡餅有很多種,遊戲者事先根據自己的口味,對各種餡餅依次打了分。同時,在8-308電腦的遙控下,各種餡餅下落的速度也是不一樣的,下落速度以格/秒爲單位。

當餡餅在某一秒末恰好到達遊戲者所在的格子中,遊戲者就收集到了這塊餡餅。

寫一個程序,幫助我們的遊戲者收集餡餅,使得所收集餡餅的分數之和最大。

輸入

輸入文件的第一行是用空格隔開的兩個正整數,分別給出了舞臺的寬度W(1到99之間的奇數)和高度H(1到100之間的整數)。

接下來依餡餅的初始下落時間順序給出了所有餡餅的信息。每一行給出了一塊餡餅的信息。由四個正整數組成,分別表示了餡餅的初始下落時刻(0到1000秒),水平位置、下落速度(1到100)以及分值。遊戲開始時刻爲0。從1開始自左向右依次對水平方向的每格編號。

輸入文件中同一行相鄰兩項之間用一個或多個空格隔開。

輸出

輸出文件的第一行給出了一個正整數,表示你的程序所收集的最大分數之和。

其後的每一行依時間順序給出了遊戲者每秒的決策。輸出0表示原地不動、1或2表示向右移動一步或兩步、-1 或-2表示向左移動一步或兩步。輸出應持續到遊戲者收集完他要收集的最後一塊餡餅爲止。

樣例輸入

3 3
0 1 2 5 
0 2 1 3
1 2 1 3
1 3 1 4

樣例輸出

12
-1
1
1

注意只有恰好某個時間餡餅在最底層才能接住

#include <iostream>
#include <cstdio>

using namespace std;

#define INF 9999999

int w,h;
int dp[1001][101];
int sel[1001][101];
int mat[1001][101];

void PrintAns(int Floor,int Pos);

int main()
{
	freopen("freepizza.in","r",stdin);
	freopen("freepizza.out","w",stdout);

	scanf("%d%d",&w,&h);

	int cnt=0;
	int s,pos,v,grade;
	int lasts;
	lasts=0;
	while(scanf("%d%d%d%d",&s,&pos,&v,&grade)==4)
	{
		if((h-1)%v==0 || s==0)
		{
			mat[s+(h-1)/v][pos]+=grade;
			lasts=max(lasts,s+(h-1)/v);
			cnt++;
		}
	}
	if(!cnt)
	{
		printf("0\n");
		return 0;
	}
	for(int i=1;i<=w;i++)
		dp[0][i]=-INF;
	dp[0][w/2+1]=mat[0][w/2+1];
	for(int i=1;i<=lasts;i++)
	{
		for(int j=1;j<=w;j++)
		{
			int maxx=-INF;

			if(j>=3)
			{
                if(maxx<dp[i-1][j-2])
                {
					maxx=dp[i-1][j-2];
					sel[i][j]=2;
                }
			}
			if(j>=2)
			{
				if(maxx<dp[i-1][j-1])
				{
					maxx=dp[i-1][j-1];
					sel[i][j]=1;
				}
			}
			if(maxx<dp[i-1][j])
			{
				maxx=dp[i-1][j];
				sel[i][j]=0;
			}
			if(j<=w-1)
			{
				if(maxx<dp[i-1][j+1])
				{
					maxx=dp[i-1][j+1];
					sel[i][j]=-1;
				}
			}
			if(j<=w-2)
			{
				if(maxx<dp[i-1][j+2])
				{
					maxx=dp[i-1][j+2];
					sel[i][j]=-2;
				}
			}
			dp[i][j]=maxx+mat[i][j];
		}
	}
	int maxi;
	int maxx=-INF;
	for(int i=1;i<=w;i++)
	{
		if(maxx<dp[lasts][i])
		{
			maxx=dp[lasts][i];
			maxi=i;
		}
	}

	printf("%d\n",maxx);

	PrintAns(lasts,maxi);
	if(lasts==0) printf("0\n");

	return 0;
}

void PrintAns(int Floor,int Pos)
{
	if(Floor<1) return;
	PrintAns(Floor-1,Pos-sel[Floor][Pos]);
	printf("%d\n",sel[Floor][Pos]);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章