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:
// state expression:
// dp[i][j][k] = max survivors
// i,j: moving dist
// k: whistling times
//
// find the answer:
// max dp[i][j][t]
//
// transferring:
// dp[x][y][k] = cnt[x][y] + max dp[lx][ly][k-1]
//
// boundary:
// dp[0][0][0] = 0
// others = -INF
//
// find the way:
// if dp[nx][ny][k+1] == cnt[nx][ny] + dp[x][y][k] and feas[nx][ny][k+1]
// way[x][y][k] = c[p]
// feas[x][y][k] = true
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_N 1005
#define MAX_T 65
#define MAX_K 35
#define INF 10000000 using namespace std; const int dx[]={,,,-};
const int dy[]={,,-,};
const char c[]={'E','N','S','W'}; int n,m,t;
int ans=;
int cx[MAX_N];
int cy[MAX_N];
int gx[MAX_N];
int gy[MAX_N];
int cnt[MAX_T][MAX_T];
int dp[MAX_T][MAX_T][MAX_K];
bool feas[MAX_T][MAX_T][MAX_K];
char way[MAX_T][MAX_T][MAX_K]; void read()
{
cin>>n>>m>>t;
for(int i=;i<n;i++)
{
cin>>cx[i]>>cy[i];
}
for(int i=;i<m;i++)
{
cin>>gx[i]>>gy[i];
}
} void cal_cnt()
{
memset(cnt,,sizeof(cnt));
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
int x=gx[j]-cx[i];
int y=gy[j]-cy[i];
if(abs(x)+abs(y)<=t) cnt[x+][y+]++;
}
}
} void cal_dp()
{
for(int k=;k<=t;k++)
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
dp[i][j][k]=-INF;
}
}
}
dp[][][]=;
for(int k=;k<=t;k++)
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
if(i+j->t) continue;
for(int p=;p<;p++)
{
int lx=i-dx[p];
int ly=j-dy[p];
dp[i][j][k]=max(dp[i][j][k],cnt[i][j]+dp[lx][ly][k-]);
}
ans=max(ans,dp[i][j][k]);
}
}
}
} void cal_way()
{
memset(feas,false,sizeof(feas));
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
if(dp[i][j][t]==ans) feas[i][j][t]=true;
}
}
for(int k=t-;k>=;k--)
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
for(int p=;p<;p++)
{
int nx=i+dx[p];
int ny=j+dy[p];
if(dp[nx][ny][k+]==cnt[nx][ny]+dp[i][j][k] && feas[nx][ny][k+])
{
way[i][j][k]=c[p];
feas[i][j][k]=true;
break;
}
}
}
}
}
} void solve()
{
cal_cnt();
cal_dp();
cal_way();
} void print()
{
cout<<ans<<endl;
int x=;
int y=;
for(int k=;k<t;k++)
{
cout<<way[x][y][k];
for(int p=;p<;p++)
{
if(way[x][y][k]==c[p])
{
x+=dx[p];
y+=dy[p];
break;
}
}
}
} int main()
{
read();
solve();
print();
}
BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机:dp【找转移路径】的更多相关文章
- BZOJ 1605 [Usaco2008 Open]Crisis on the Farm 牧场危机 DP
题意:链接 方法: DP 解析: 第一眼搜索题,复杂度不同意dfs,并且牛的数量太多不能bfs,迭代更不可能,A*不会估价.可能记忆化? 等等记忆化我还搜个毛线- 直接改成DP就好了. 状态非常好想非 ...
- BZOJ1605 [Usaco2008 Open]Crisis on the Farm 牧场危机
标题好长&&我是权限狗,汪汪! 题没看懂的我以为这是一道极难滴题目...然后,然后我就看懂题了. 数据少给了一个条件K <= 30...(没这条件还做个鬼...) f[k, i, ...
- BZOJ 1621: [Usaco2008 Open]Roads Around The Farm分岔路口
题目 1621: [Usaco2008 Open]Roads Around The Farm分岔路口 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 56 ...
- BZOJ 1621 [Usaco2008 Open]Roads Around The Farm分岔路口:分治 递归
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1621 题意: 约翰的N(1≤N≤1,000,000,000)只奶牛要出发去探索牧场四周的土 ...
- bzoj 1621: [Usaco2008 Open]Roads Around The Farm分岔路口【dfs】
模拟就行--讲道理这个时间复杂度为啥是对的??? #include<iostream> #include<cstdio> using namespace std; int k, ...
- bzoj 1231: [Usaco2008 Nov]mixup2 混乱的奶牛 -- 状压DP
1231: [Usaco2008 Nov]mixup2 混乱的奶牛 Time Limit: 10 Sec Memory Limit: 162 MB Description 混乱的奶牛 [Don Pi ...
- BZOJ 1616 [Usaco2008 Mar]Cow Travelling游荡的奶牛:dp【网格型】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1616 题意: 有一个n*m的网格. '.'表示平坦的草地,'*'表示挡路的树(不能走). ...
- bzoj 1609[Usaco2008 Feb]Eating Together麻烦的聚餐【dp】
设up[i][j]为第i位升序为j的最小修改数,down为降序 #include<iostream> #include<stdio.h> using namespace std ...
- bzoj 1616: [Usaco2008 Mar]Cow Travelling游荡的奶牛【dp】
写了个bfs发现MLE了... 设f[t][i][j]为在t时刻走到(i,j)的方案数,转移和bfs一样 #include<iostream> #include<cstdio> ...
随机推荐
- Win7如何获得TrustedInstaller权限
将下面的信息保存为启用TakeOwnership.reg,双击注册即可 Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\sh ...
- mongodb分片片键的选择(持续更新中)
首先要了解项目的情况,检查使用情况 对集合进行分片时,要选择一个或者两个字段拆分数据,这个键叫做片键 一旦拥有对个分片,在修改片键几乎是不肯能的事情,因此选择合适的片键是非常重要的. 对集合分片之前要 ...
- remove-duplicates-from-sorted-array-ii——去除重复
Follow up for "Remove Duplicates":What if duplicates are allowed at most twice? For exampl ...
- 通过a标签(不丢失referrer)打开另一个窗口
第一页 //这个是显示窗口的方法 function frmshow(arr){ var old; var val =$.trim($("#phone").val()); if (v ...
- web前端的一些实用技能
如今我们使用的互联网,客户端与服务器端的交互无时无刻不在发生.比如我们在浏览器打开网页,浏览器就是客户端,将网页数据发过来的也就是服务器.其实服务器,并没有什么特别的,也就是一台昼夜不停运转的电脑罢了 ...
- Android微信分享功能实例+demo
Android微信分享功能实例 1 微信开放平台注册 2 获得appId,添加到程序中,并运行程序 3 使用应用签名apk生成签名,添加到微信开放平台应用签名,完成注册 4 测试分享功能. 有问题请留 ...
- GitHub上编程语言流行度分析
GitHub已然是全球最流行的开源项目托管平台,项目数量眼下已经达到了千万级别.Adereth在Counting Stars on GitHub一文提供了一个很有意思的思路,那就是籍GitHub用户通 ...
- sprint3 【每日scrum】 TD助手站立会议第四天
站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 和楠哥学习了通过AlarmManager 来实现闹钟,由于要用到BroadcastReceiver广播协议,所以正在学习中,暂时只是按照教程写 ...
- 程序猿的量化交易之路(32)--Cointrade之Portfolio组合(19)
转载须注明出处:http://blog.csdn.net/minimicall?viewmode=contents,http://cloudtrade.top/ Portfolio:组合,代表的是多个 ...
- anaconda3.5 3.6 2.7
https://repo.continuum.io/archive/ Filename Size Last Modified MD5 Anaconda2-5.0.1-Linux-x86.sh 413. ...