bzoj 1605: [Usaco2008 Open]Crisis on the Farm 牧场危机(DP)

1605: [Usaco2008 Open]Crisis on the Farm 牧场危机

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 403   Solved: 145
[ Submit][ Status][ Discuss]

Description

约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆一堆,共N(1≤N≤1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场里还有M(1≤M≤1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有的牛塔向东南西北四个方向移动一格.
    每一次,当一个牛塔到达了一个草垛所在的格子,牛塔最上方的奶牛就会跳到草垛上,而且不再下来,而其他奶牛仍然呈塔状站在草垛所在的格子里.当牛塔只剩一只奶牛时,这只奶牛也会跳到草垛上. 突然,约翰大惊失色:原来邻家的奶缸爆炸了!滚滚而下的牛奶正朝着约翰的牧场冲来,不久就要将牧场淹没.约翰必须马上行动,用口哨声挽救奶牛们的生命.他要指挥奶牛尽量多地跳上草垛,草垛上的奶牛将不会被淹死.    约翰还有K次吹口哨的机会.那他最多还能救多少奶牛呢?请计算最多能挽救的奶牛数,以及达到这个数目约翰需要吹的口哨调子序列.序列用E,W,S,N表示东西南北.如果有多种序列能达到
要求,输出作为字符串最小的.

Input

第1行输入三个整数N,M,K,之后N行每行输入一对整数(Xi,Yi)表示一座牛塔所在的位置,1<=K<=30
之后M行每行输入一对整数(Xi,Yi)表示一个草垛所在的位置.1≤Xi≤1000;1≤Yi≤1000.

Output

    第1行输出最多能挽救的奶牛数.第2行输出口哨调子序列.

Sample Input

3 6 3
3 4
6 2
5 7
8 2
9 2
6 4
5 4
6 7
8 7

Sample Output

6
EEE


dp[k][i][j]表示第k步所有奶牛的总体偏移量为(i, j)的最大挽救数

因为i, j可以为负,所以要整体+k

还要输出路径,反过来DFS一遍是必须的

不好写


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef struct
{
	int x;
	int y;
}Point;
Point s1[1005], s2[1005];
int cnt[66][66], dp[33][66][66], dir[4][2] = {1,0,0,1,0,-1,-1,0};
char ans[33][66][66], Q[5] = "WSNE";
int main(void)
{
	int n, m, k, i, j, p, bet, f, q;
	scanf("%d%d%d", &n, &m, &k);
	for(i=1;i<=n;i++)
		scanf("%d%d", &s1[i].x, &s1[i].y);
	for(i=1;i<=m;i++)
		scanf("%d%d", &s2[i].x, &s2[i].y);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(abs(s1[i].x-s2[j].x)>k || abs(s1[i].y-s2[j].y)>k)
				continue;
			cnt[31+s1[i].x-s2[j].x][31+s1[i].y-s2[j].y]++;
		}
	}
	memset(ans, 'Z', sizeof(ans));
	memset(dp, -62, sizeof(dp));
	bet = 0;
	dp[0][31][31] = 0;
	for(p=1;p<=k;p++)
	{
		for(i=1;i<=62;i++)
		{
			for(j=1;j<=62;j++)
			{
				dp[p][i][j] = max(max(dp[p-1][i-1][j], dp[p-1][i][j-1]), max(dp[p-1][i+1][j], dp[p-1][i][j+1]))+cnt[i][j];
				if(p==k)
					bet = max(bet, dp[p][i][j]);
			}
		}
	}
	for(i=1;i<=62;i++)
	{
		for(j=1;j<=62;j++)
		{
			if(dp[k][i][j]==bet)
				ans[k][i][j] = 'A';
		}
	}
	for(p=k-1;p>=0;p--)
	{
		for(i=1;i<=62;i++)
		{
			for(j=1;j<=62;j++)
			{
				for(f=0;f<=3;f++)
				{
					if(dp[p][i][j]+cnt[i+dir[f][0]][j+dir[f][1]]==dp[p+1][i+dir[f][0]][j+dir[f][1]] && ans[p+1][i+dir[f][0]][j+dir[f][1]]<'Z')
						ans[p][i][j] = Q[f];
				}
			}
		}
	}
	p = q = 31;
	printf("%d\n", bet);
	for(i=0;i<=k-1;i++)
	{
		printf("%c", ans[i][p][q]);
		switch(ans[i][p][q])
		{
			case 'E': p--; break;
			case 'W': p++; break;
			case 'S': q++; break;
			case 'N': q--;
		}
	}
	printf("\n");
	return 0;
}


相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页