zoukankan      html  css  js  c++  java
  • BZOJ1605: [Usaco2008 Open]Crisis on the Farm 牧场危机

    n<=1000个牛塔,每塔30头牛,m<=1000个地点会使经过的牛塔少一头,K<=30个命令每次使所有牛塔往东西南北某方走一格,求最多损失多少牛并输出字典序最小的方案。

    没看到K的范围想不出系列。。由于K<=30,不会出现牛负数的情况,所以直接搜,搜可能会搜到重复,那就记忆化,那不如直接写DP。

    f(k,i,j)--走了k步,所有牛相对原来横坐标走了i纵坐标走了j,f(k,i,j)=max f(k-1,四个方向) +s(i,j),其中s(i,j)表示所有牛往右走i格往上走j格(i,j可以是负数)损失的牛,这可以预处理。

    最后的方案要字典序最小。由于某个最优状态的i,j是一定的,也就是W-E的数量和N-S的数量是一定的,那后面的W越多,前面的E就越多,字典序就越小,而DP记状态是从后往前走的,所以字典序大的优先选,W->S->N->E,在dp值相同时按这个顺序取就行了。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stdlib.h>
     4 //#include<math.h>
     5 #include<algorithm>
     6 //#include<iostream>
     7 using namespace std;
     8 
     9 int n,m,K;
    10 #define maxn 1011
    11 int f[66][66][66],pre[66][66][66],s[66][66];
    12 struct Point{int x,y;}a[maxn];bool mp[maxn][maxn];
    13 char c[66],ss[66];int ls,lss=0;
    14 bool check()
    15 {
    16     if (!lss) return 1;
    17     for (int i=ls-1;i>=0;i--)
    18         if (c[i]!=ss[i]) return c[i]<ss[i];
    19     return 0;
    20 }
    21 const int inf=0x3f3f3f3f;
    22 int ans=0;
    23 int main()
    24 {
    25     scanf("%d%d%d",&n,&m,&K);int x,y;
    26     for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    27     for (int i=1;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=1;
    28     memset(s,0,sizeof(s));
    29     for (int i=-30;i<=30;i++)
    30         for (int j=-30;j<=30;j++)
    31         {
    32             for (int k=1;k<=n;k++)
    33                 if (a[k].x+i>0 && a[k].x+i<1011 && a[k].y+j>0 && a[k].y+j<1011)
    34                     if (mp[a[k].x+i][a[k].y+j]) s[i+30][j+30]++;
    35         }
    36     for (int i=0;i<=60;i++)
    37         for (int j=0;j<=60;j++)
    38             f[0][i][j]=-inf;
    39     f[0][30][30]=0;
    40     for (int k=1;k<=K;k++)
    41         for (int i=-30;i<=30;i++)
    42             for (int j=-30;j<=30;j++)
    43             {
    44                 int x=i+30,y=j+30;
    45                 f[k][x][y]=-inf;
    46                 if (x<60 && f[k-1][x+1][y]+s[x][y]>f[k][x][y])
    47                 {
    48                     f[k][x][y]=f[k-1][x+1][y]+s[x][y];
    49                     pre[k][x][y]='W';
    50                 }
    51                 if (y<60 && f[k-1][x][y+1]+s[x][y]>f[k][x][y])
    52                 {
    53                     f[k][x][y]=f[k-1][x][y+1]+s[x][y];
    54                     pre[k][x][y]='S';
    55                 }
    56                 if (y && f[k-1][x][y-1]+s[x][y]>f[k][x][y])
    57                 {
    58                     f[k][x][y]=f[k-1][x][y-1]+s[x][y];
    59                     pre[k][x][y]='N';
    60                 }
    61                 if (x && f[k-1][x-1][y]+s[x][y]>f[k][x][y])
    62                 {
    63                     f[k][x][y]=f[k-1][x-1][y]+s[x][y];
    64                     pre[k][x][y]='E';
    65                 }
    66                 if (k==K) ans=max(ans,f[k][x][y]);
    67             }
    68     printf("%d
    ",ans);
    69     for (int i=0;i<=60;i++)
    70         for (int j=0;j<=60;j++)
    71             if (f[K][i][j]==ans)
    72             {
    73                 int t=K,x=i,y=j;ls=0;
    74                 while (t)
    75                 {
    76                     c[ls++]=pre[t][x][y];
    77                     switch (pre[t][x][y])
    78                     {
    79                         case 'W':x++;break;
    80                         case 'S':y++;break;
    81                         case 'N':y--;break;
    82                         case 'E':x--;break;
    83                     }
    84                     t--;
    85                 }
    86                 if (check()) memcpy(ss,c,sizeof(c)),lss=ls;
    87             }
    88     for (int i=ls-1;i>=0;i--) putchar(ss[i]);
    89     return 0;
    90 }
    View Code

    注意一下下标不要访问到-1或者61否则会出奇怪错误。

  • 相关阅读:
    敏捷结果30天之第十七天:找出高效时间,并利用它来处理重要事情
    每天一个linux命令(13):less 命令
    敏捷结果30天之第十九天:你在为谁做事
    每天一个linux命令(6):rmdir 命令
    每天一个linux命令(11):nl命令
    代码重构学习笔记三:重构72招式
    每天一个linux命令(4):mkdir命令
    敏捷结果30天之第二十二天:设计你的一天
    敏捷结果30天之第二十一天:正面失败,吸取教训,改善结果
    每天一个linux命令(8):cp 命令
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7608148.html
Copyright © 2011-2022 走看看