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

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

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 288   Solved: 95
[ 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

Use the 'east' whistle three times, at which point the milk floods
the area. Each haystack ends up saving 1 cow.

6
EEE


这题做得实在是。。。。(省略1E9呵呵)
思路嘛就是dp..f[k][i][j]代表吹k下x轴移动i-k,y轴移动j-k的最佳状态,转移不是很难。。
But!!!!!!!!!!!!!!!!
这些牛的位置可以到任意小于0的点或者是大于一千哈哈哈哈哈哈
然后由于我是边做边转移解的状态。。忽略了第一次吹哨,且没拯救牛的情况。。。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;


const int maxn = 80;
const int dx[4] = {1,0,-1,0};
const int dy[4] = {0,1,0,-1};
const char d[4] = {'W','S','E','N'};


struct W{
char a[maxn];
bool operator < (const W &b) const{
for (int l = 1; l <= maxn; l++)
{
if (a[l] < b.a[l]) return true;
if (a[l] > b.a[l]) return false;
}
}
}w[maxn][maxn][maxn];


struct C{
int x,y;
}cow[1010];


int f[maxn][maxn][maxn],Map[1010][1010],n,m,k,i,j,cnt[maxn][maxn];
bool vis[maxn][maxn][maxn];


int main()
{
//freopen("yzy.txt","r",stdin);
cin >> n >> m >> k;
memset(Map,0,sizeof(Map));
memset(f,0,sizeof(f));
memset(vis,false,sizeof(vis));
for (i = 1; i <= n; i++) scanf("%d%d",&cow[i].x,&cow[i].y);
for (i = 1; i <= m; i++) 
{
int x,y;
scanf("%d%d",&x,&y);
Map[x][y] = 1;
}
for (int l = 1; l <= n; l++)
 for (i = 0; i <= 2*k; i++)
   for (j = 0; j <= 2*k; j++)
   {
      int xx = cow[l].x + i - k;
      int yy = cow[l].y + j - k;
      if (xx < 0 || xx > 1000 || yy < 0 || yy > 1000) 
{
  continue;
}
      cnt[i][j] += Map[xx][yy];
   }
f[0][k][k] = 0;
vis[0][k][k] = true;
for (int l = 1; l <= k; l++)
 for (i = 0; i <= 2*k; i++)
   for (j = 0; j <= 2*k; j++)
     for (int L = 0; L < 4; L++)
     {
      int xx = i + dx[L];
      int yy = j + dy[L];
      if (xx < 0 || xx > 2*k || yy < 0 || yy > 2*k || !vis[l-1][xx][yy]) continue;
      vis[l][i][j] = true;
      if (f[l][i][j] < f[l-1][xx][yy] + cnt[i][j])
      {
      f[l][i][j] = f[l-1][xx][yy] + cnt[i][j];
      w[l][i][j] = w[l-1][xx][yy];
      w[l][i][j].a[l] = d[L];
      }
      else
      if (f[l][i][j] == f[l-1][xx][yy] + cnt[i][j])
      {
      W K;
      K = w[l-1][xx][yy];
      K.a[l] = d[L];
      if (K < w[l][i][j] || f[l][i][j] == 0) w[l][i][j] = K;
      }
     }
int ans = -1,I,J;
  for (i = 0; i <= 2*k; i++)
 for (j = 0; j <= 2*k; j++)
   if (f[k][i][j] > ans)
   {
    ans = f[k][i][j];
    I = i; J = j;
   }
   else 
if (f[k][i][j] == ans)
   {
    if (w[k][i][j] < w[k][I][J])
    {
    I = i;J = j;
    }
   }
printf("%d\n",ans);
for (i = 1; i <= k; i++) cout << w[k][I][J].a[i];
return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值