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 }
时间: 2024-10-08 19:57:23

BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机:dp【找转移路径】的相关文章

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

标题好长&&我是权限狗,汪汪! 题没看懂的我以为这是一道极难滴题目...然后,然后我就看懂题了. 数据少给了一个条件K <= 30...(没这条件还做个鬼...) f[k, i, j]表示走了k步,x方向移动i,y方向移动j的最大被拯救牛的数量,然后方程就很好写了,略之. (其实是太烦了,不想写) 真是一道很烦的题目...不仅预处理很烦,转移很烦,连输出解也很烦... 1 /*******************************************************

洛谷 P2905 [USACO08OPEN]农场危机Crisis on the Farm(恶心的DP)

P2905 [USACO08OPEN]农场危机Crisis on the Farm 1605: [Usaco2008 Open]Crisis on the Farm 牧场危机 题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场 里还有M(1 < M < 1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有 的牛塔向东南

bzoj:1621: [Usaco2008 Open]Roads Around The Farm分岔路口

Description 约翰的N(1≤N≤1,000,000,000)只奶牛要出发去探索牧场四周的土地.她们将沿着一条路走,一直走到三岔路口(可以认为所有的路口都是这样的).这时候,这一群奶牛可能会分成两群,分别沿着接下来的两条路继续走.如果她们再次走到三岔路口,那么仍有可能继续分裂成两群继续走.    奶牛的分裂方式十分古怪:如果这一群奶牛可以精确地分成两部分,这两部分的牛数恰好相差K(1≤K≤1000),那么在三岔路口牛群就会分裂.否则,牛群不会分裂,她们都将在这里待下去,平静地吃草.   

BZOJ 1621 [Usaco2008 Open]Roads Around The Farm分岔路口:分治 递归

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1621 题意: 约翰的N(1≤N≤1,000,000,000)只奶牛要出发去探索牧场四周的土地. 她们将沿着一条路走,一直走到三岔路口(可以认为所有的路口都是这样的). 这时候,这一群奶牛可能会分成两群,分别沿着接下来的两条路继续走. 如果她们再次走到三岔路口,那么仍有可能继续分裂成两群继续走. 奶牛的分裂方式十分古怪:如果这一群奶牛可以精确地分成两部分,这两部分的牛数恰好相差K(1≤K≤

BZOJ 1616 [Usaco2008 Mar]Cow Travelling游荡的奶牛:dp【网格型】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1616 题意: 有一个n*m的网格. '.'表示平坦的草地,'*'表示挡路的树(不能走). 有一只奶牛,第0秒时在(r1,c1),第t秒时在(r1,c2). 它每一秒钟都会向上下左右任一方向走一格,不会停留不动. 问你在这t秒钟内,奶牛可能的移动路径数. 题解: 表示状态: dp[i][j][k]:表示在第k秒,走到了位置(i,j)时的方案数. 找出答案: ans = dp[r2][c2]

bzoj1621[Usaco2008 Open]Roads Around The Farm分岔路口*

bzoj1621[Usaco2008 Open]Roads Around The Farm分岔路口 题意: n头牛在路上走,每当它们走到岔路,如果这些牛可以分为数量相差刚好为k的两群,那么它们就会分成这样的两群往前走,否则就会停下来吃草.问最后有多少群在吃草.n≤10^9,k≤1000. 题解: 暴力模拟.(好像实际上不管有多少只牛只要经过3.4个岔路后就会无法再分并停下来吃草) 代码: 1 #include <cstdio> 2 int n,k,ans; 3 void dfs(int n,i

洛谷P2905 [USACO08OPEN]农场危机Crisis on the Farm

P2905 [USACO08OPEN]农场危机Crisis on the Farm 题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每一堆里,30只奶牛一只踩在另一只的背上,叠成一座牛塔.牧场 里还有M(1 < M < 1000)个高高的草垛. 作为出色的指挥家,约翰可以通过口哨指挥奶牛们移动.他的口哨有四个音,分别能使所有 的牛塔向东南西北四个方向移动一格. 每一次,当一个牛塔到达了一个草垛所在的格子,牛塔最上方的奶牛就会跳到

[bzoj 1911][Apio 2010]特别行动队(斜率优化DP)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 分析: 首先可以的到裸的方程f[i]=max{f[j]+a*(Si-Sj)^2+b*(Si-Sj)+c} 0<j<i 简化一下方程,我们知道对于一次项,最后结果肯定是b*Sn 所以可以写成f[i]=max{f[j]+a*(Si-Sj)^2+c} 0<j<i 我们不妨设0<x<y<i,且x比y优 即f[x]+a*(Si-Sx)^2+c>f[y]+a*

BZOJ 1093 最大半连通子图(强连通分量+树形DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1093 题意: 思路:(1)首先,强连通分量中的一个点若在最大半连通子图中,则必定整个连通分量中的点都在,因为都在还是满足半连通的性质而且使得节点数更多. (2)因此,求出强连通分量缩点,形成一个有向无环图,其实与树是差不多的.在这个图上DP一次即可,也就是找出最长链以及最长链的个数. vector<int> g[N],g1[N]; int n,m,mod; int dfn[N],lo