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 }

 

posted @ 2017-09-27 03:13  Leohh  阅读(178)  评论(0编辑  收藏  举报