zoukankan      html  css  js  c++  java
  • BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机:dp【找转移路径】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1605

    题意:

      平面直角坐标系中,有n个点,m个标记(坐标范围1~1000)。

      你可以发出口令,让所有点整体向东、南、西、北四个方向中的任意一个方向移动,口令分别记作'E','S','W','N'。

      每当一个点碰到一个标记,则答案+1。(保证初始时没有点在标记上)

      你最多可以发出t次口令。

      问你答案最大是多少,并输出字典序最小的口令序列。

    题解:

      表示状态:

        dp[i][j][k] = max survivors

        i:水平方向共移动了i个单位(左负右正)

        j:竖直方向共移动了j个单位(下负上正)

        k:发了k次口令

        (因为数组下标有负数,所以最后再给i,j统一加上30就好啦,现在先不管它)

      找出答案:

        max dp[i][j][k]

      如何转移:

        先预处理cnt数组:cnt[x][y]表示移动了(x,y)时,碰到标记的点的个数。

        dp[x][y][k] = cnt[x][y] + max dp[lx][ly][k-1]

        lx=i-dx[p], ly=j-dy[p] (p = 0 to 3)

      边界条件:

        dp[0][0][0] = 0

        others = -INF(不存在)

      输出序列:

        说明:

          (1)feas[x][y][k],用来判断最终答案是否由状态(x,y,k)转移而来。

          (2)way[x][y][k],表示在状态(x,y,k)时发出的口令。

        总共三步:

          (1)先将feas全部设为false,再将最终答案的feas改为true。

          (2)枚举k(从大到小),i,j,判断当前(i,j,k)是否能转移到最终答案。如果能,更新当前way和feas。

          (3)枚举k(从小到大),当前位置为(x,y),输出way[x][y][k],并更新(x,y)。

    AC Code:

      1 // state expression:
      2 // dp[i][j][k] = max survivors
      3 // i,j: moving dist
      4 // k: whistling times
      5 //
      6 // find the answer:
      7 // max dp[i][j][t]
      8 //
      9 // transferring:
     10 // dp[x][y][k] = cnt[x][y] + max dp[lx][ly][k-1]
     11 //
     12 // boundary:
     13 // dp[0][0][0] = 0
     14 // others = -INF
     15 //
     16 // find the way:
     17 // if dp[nx][ny][k+1] == cnt[nx][ny] + dp[x][y][k] and feas[nx][ny][k+1]
     18 // way[x][y][k] = c[p]
     19 // feas[x][y][k] = true
     20 #include <iostream>
     21 #include <stdio.h>
     22 #include <string.h>
     23 #include <stdlib.h>
     24 #define MAX_N 1005
     25 #define MAX_T 65
     26 #define MAX_K 35
     27 #define INF 10000000
     28 
     29 using namespace std;
     30 
     31 const int dx[]={1,0,0,-1};
     32 const int dy[]={0,1,-1,0};
     33 const char c[]={'E','N','S','W'};
     34 
     35 int n,m,t;
     36 int ans=0;
     37 int cx[MAX_N];
     38 int cy[MAX_N];
     39 int gx[MAX_N];
     40 int gy[MAX_N];
     41 int cnt[MAX_T][MAX_T];
     42 int dp[MAX_T][MAX_T][MAX_K];
     43 bool feas[MAX_T][MAX_T][MAX_K];
     44 char way[MAX_T][MAX_T][MAX_K];
     45 
     46 void read()
     47 {
     48     cin>>n>>m>>t;
     49     for(int i=0;i<n;i++)
     50     {
     51         cin>>cx[i]>>cy[i];
     52     }
     53     for(int i=0;i<m;i++)
     54     {
     55         cin>>gx[i]>>gy[i];
     56     }
     57 }
     58 
     59 void cal_cnt()
     60 {
     61     memset(cnt,0,sizeof(cnt));
     62     for(int i=0;i<n;i++)
     63     {
     64         for(int j=0;j<m;j++)
     65         {
     66             int x=gx[j]-cx[i];
     67             int y=gy[j]-cy[i];
     68             if(abs(x)+abs(y)<=t) cnt[x+30][y+30]++;
     69         }
     70     }
     71 }
     72 
     73 void cal_dp()
     74 {
     75     for(int k=0;k<=t;k++)
     76     {
     77         for(int i=0;i<=60;i++)
     78         {
     79             for(int j=0;j<=60;j++)
     80             {
     81                 dp[i][j][k]=-INF;
     82             }
     83         }
     84     }
     85     dp[30][30][0]=0;
     86     for(int k=1;k<=t;k++)
     87     {
     88         for(int i=0;i<=60;i++)
     89         {
     90             for(int j=0;j<=60;j++)
     91             {
     92                 if(i+j-60>t) continue;
     93                 for(int p=0;p<4;p++)
     94                 {
     95                     int lx=i-dx[p];
     96                     int ly=j-dy[p];
     97                     dp[i][j][k]=max(dp[i][j][k],cnt[i][j]+dp[lx][ly][k-1]);
     98                 }
     99                 ans=max(ans,dp[i][j][k]);
    100             }
    101         }
    102     }
    103 }
    104 
    105 void cal_way()
    106 {
    107     memset(feas,false,sizeof(feas));
    108     for(int i=0;i<=60;i++)
    109     {
    110         for(int j=0;j<=60;j++)
    111         {
    112             if(dp[i][j][t]==ans) feas[i][j][t]=true;
    113         }
    114     }
    115     for(int k=t-1;k>=0;k--)
    116     {
    117         for(int i=0;i<=60;i++)
    118         {
    119             for(int j=0;j<=60;j++)
    120             {
    121                 for(int p=0;p<4;p++)
    122                 {
    123                     int nx=i+dx[p];
    124                     int ny=j+dy[p];
    125                     if(dp[nx][ny][k+1]==cnt[nx][ny]+dp[i][j][k] && feas[nx][ny][k+1])
    126                     {
    127                         way[i][j][k]=c[p];
    128                         feas[i][j][k]=true;
    129                         break;
    130                     }
    131                 }
    132             }
    133         }
    134     }
    135 }
    136 
    137 void solve()
    138 {
    139     cal_cnt();
    140     cal_dp();
    141     cal_way();
    142 }
    143 
    144 void print()
    145 {
    146     cout<<ans<<endl;
    147     int x=30;
    148     int y=30;
    149     for(int k=0;k<t;k++)
    150     {
    151         cout<<way[x][y][k];
    152         for(int p=0;p<4;p++)
    153         {
    154             if(way[x][y][k]==c[p])
    155             {
    156                 x+=dx[p];
    157                 y+=dy[p];
    158                 break;
    159             }
    160         }
    161     }
    162 }
    163 
    164 int main()
    165 {
    166     read();
    167     solve();
    168     print();
    169 }
  • 相关阅读:
    状态模式作业
    建造者模式作业
    关于 IIS 上的 Speech 设置
    装饰模式作业
    《软件架构与设计模式》关于 抽象工厂模式 的一个小例子
    谈一谈为什么我要创建个人博客
    C#网站发布在IIS10上,Access数据库读取为空白的解决方案
    广义表 Head Tail
    c# asp.net4.0尚未在web服务器上注册
    装饰者模式(例子)
  • 原文地址:https://www.cnblogs.com/Leohh/p/7599800.html
Copyright © 2011-2022 走看看