BestCoder14 1002.Harry And Dig Machine(hdu 5067) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5067
题目意思:给出一个 n * m 的方格,每一个小方格(大小为1*1)的值要么为 0 要么为一个正整数。规定是正整数的值得方格个数不超过 10 个。现在问从最左上角的点开始,要经过所有正整数的值的点之后,要返回到最左上角的点的最短路径是多少。
其实为正整数的那些点具体值是什么根本无关紧要。可以先求出所有点到其他点的两两最短路径,然后利用状态压缩 (考虑到只有10个点,状态数最多为2^10)来求出答案),题解是这样说的:
dp[i][j]:表示状态 i 的点被访问过了,当前停留在点 j 需要的最少时间。枚举另一个不在状态 i 内的点 k , 从点 j 走到点 k 的状态转移方程为:
dp[i|(1<<k)][k] = min(dp[i|(1<<k)][k], dp[i][j] + dist(j, k))
其中,dist[j][k] 表示从点 j 与 点 k 的最短距离。所以可以利用 bfs(当然有更简单的解法,这里我是为了练手而已) 求出以每一个点作为出发点,求出以这个点到其他所有点的最短距离。
代码中的 dp 计算,和方程有一点点不同。有些地方不太理解,先留着吧。。。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std; const int maxn = + ;
const int INF = 0x3f3f3f3f;
int n, m, cnt, st[maxn], end[maxn];
int vis[maxn][maxn], hs[maxn][maxn];
int dp[maxn][<<], dist[maxn][maxn]; int dx[] = {, , , -};
int dy[] = {, , -, }; struct node
{
int x, y;
int step;
} cur, tmp; queue<node> q; void bfs(int id)
{
while (!q.empty())
q.pop();
memset(vis, , sizeof(vis));
tmp.x = st[id], tmp.y = end[id];
tmp.step = dist[id][id] = ;
q.push(tmp);
vis[st[id]][end[id]] = ; while (!q.empty())
{
tmp = q.front();
q.pop(); for (int i = ; i < ; i++)
{
int tx = tmp.x + dx[i];
int ty = tmp.y + dy[i];
if (tx >= && tx <= n && ty >= && ty <= m && !vis[tx][ty])
{
vis[tx][ty] = ;
cur.x = tx;
cur.y = ty;
cur.step = tmp.step + ;
if (hs[tx][ty] != -) // the target point's id
dist[id][hs[tx][ty]] = cur.step;
q.push(cur);
}
}
}
} void Init()
{
memset(hs, -, sizeof(hs));
int val;
cnt = ;
for (int i = ; i <= n; i++)
{
for (int j = ; j <= m; j++)
{
scanf("%d", &val);
if (val || i == && j == )
{
st[cnt] = i;
end[cnt] = j;
hs[i][j] = cnt++; // 为每一个大于0的点(最多只有10个)编号,第一个点编号为0而不是1
}
}
}
} int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif while (scanf("%d%d", &n, &m) != EOF)
{
Init();
for (int i = ; i < cnt; i++) // the shortest path from point i to other points
bfs(i);
int status = <<cnt;
memset(dp, 0x3f, sizeof(dp)); dp[][] = ;
for (int i = ; i < status; i++)
{
for (int j = ; j < cnt; j++)
{
if (dp[j][i] != INF)
{
for (int k = ; k < cnt; k++)
{
if (!(i & (<<k))) // 点k不包含在状态i上
dp[k][i|(<<k)] = min(dp[k][i|(<<k)], dp[j][i]+dist[j][k]);
}
}
}
}
printf("%d\n", dp[][status-]);
}
return ;
}
代码中最后的输出 dp[0][status-1] 很明显就是从最左上角的点出发,经过所有正整数点的最短距离。不过为什么求的时候与二维数组dp[][]不同,这个确实不太理解。
精简版:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long Int;
typedef pair<int,int>pi;
int n,m;
vector<pi>V;
int Map[][];
int dp[][];
int getdis(int u,int v)
{
if(!u)return V[v-].first+V[v-].second-;
u--;v--;
return abs(V[v].first-V[u].first)+abs(V[v].second-V[u].second);
}
void up(int &x,int y)
{
if(x==-||x>y)x=y;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
V.clear();
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
{
int u;
scanf("%d",&u);
if(i==&&j==)continue;
if(u>)
V.push_back(pi(i,j));
}
if(!V.size()){puts("");continue;}
memset(dp,-,sizeof(dp));
dp[][]=;
int mx=(<<V.size())-;
for(int j=;j<mx;j++)
for(int k=;k<=V.size();k++)
if(dp[j][k]>=)
{
for(int p=;p<V.size();p++)
if((j&(<<p))==)
{
up(dp[j|(<<p)][p+],dp[j][k]+getdis(k,p+));
}
}
int ans=-;
for(int i=;i<V.size();i++)
if(dp[mx][i+]>=)
up(ans,dp[mx][i+]+getdis(,i+));
printf("%d\n",ans);
}
}
BestCoder14 1002.Harry And Dig Machine(hdu 5067) 解题报告的更多相关文章
- BestCoder6 1002 Goffi and Squary Partition(hdu 4982) 解题报告
题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?pid=1002&cid=530 (格式有一点点问题,直接粘 ...
- BestCoder22 1002.NPY and arithmetic progression(hdu 5143) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5143 题目意思:给出 1, 2, 3, 4 的数量,分别为a1, a2, a3, a4,问是否在每个数 ...
- BestCoder16 1002.Revenge of LIS II(hdu 5087) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5087 题目意思:找出第二个最长递增子序列,输出长度.就是说,假如序列为 1 1 2,第二长递增子序列是 ...
- BestCoder20 1002.lines (hdu 5124) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5124 题目意思:给出 n 条线段,每条线段用两个整数描述,对于第 i 条线段:xi,yi 表示该条线段 ...
- BestCoder18 1002.Math Problem(hdu 5105) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5105 题目意思:给出一个6个实数:a, b, c, d, l, r.通过在[l, r]中取数 x,使得 ...
- BestCoder17 1002.Select(hdu 5101) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5101 题目意思:给出 n 个 classes 和 Dudu 的 IQ(为k),每个classes 都有 ...
- BestCoder15 1002.Instruction(hdu 5083) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5083 题目意思:如果给出 instruction 就需要输出对应的 16-bit binary cod ...
- BestCoder12 1002.Help him(hdu 5059) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5059 题目意思:就是输入一行不多于 100 的字符串(除了'\n' 和 '\r' 的任意字符),问是否 ...
- BestCoder10 1002 Revenge of GCD(hdu 5019) 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5019 题目意思:给出 X 和 Y,求出 第 K 个 X 和 Y 的最大公约数. 例如8 16,它们的公 ...
随机推荐
- 点击div区域以外部分,div区域隐藏
核心思想: 监听body的click事件,事件触发的时候判断是否发生在弹出的div上,如果不在,关闭弹层 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTM ...
- asp.net 实现在线打印功能,jQuery打印插件PrintArea实现自动分页
使用的组件:jQuery打印插件PrintArea,有兴趣的可以研究一下. 使用方法略过,这里将介绍如何实现打印多页是可以分页. 现在提供两种方法思路: 1.根据特定的打印机型号和使用的纸张类型,然后 ...
- poj 3233 矩阵快速幂+YY
题意:给你矩阵A,求S=A+A^1+A^2+...+A^n sol:直接把每一项解出来显然是不行的,也没必要. 我们可以YY一个矩阵: 其中1表示单位矩阵 然后容易得到: 可以看出这个分块矩阵的左下角 ...
- codeforces 359D 二分答案+RMQ
上学期刷过裸的RMQ模板题,不过那时候一直不理解>_< 其实RMQ很简单: 设f[i][j]表示从i开始的,长度为2^j的一段元素中的最小值or最大值 那么f[i][j]=min/max{ ...
- SQL增加、删除、更改表中的字段名
1. 向表中添加新的字段 ) not null 2. 删除表中的一个字段 delete table table_name column column_name 3. 修改表中的一个字段名 alter ...
- Robot Framework测试框架学习笔记
一.Robot Framework框架简介 Robot Framework是一种基于Python的可扩展关键字驱动自动化测试框架,通常用于端到端的可接收测试和可接收测试驱动的开发.可以 ...
- 活用scanf
scanf()是C语言中用于读入格式化数据(formatted data)的函数. 我们可能对scanf()的一般用法已经了然,而至于scanf()读入数据的机制恐怕并不十分清楚. 下面我将比较详细地 ...
- 如何把项目托管到GitHub
第一步:先注册一个Github的账号,这是必须的 注册地址:Github官网注册入口 第二步:准备工作 gitHub网站使用Git版本管理工具来对仓库进行管理,注意它们并不等同. gitHub是全球最 ...
- eclipse中使用git
有的eclipse已经自带了Git了,就不用安装了.如果,想重新安装,可以先卸载GIT,卸载 不同eclipse卸载不一样: 1.在Eclipse中依次点击菜单"Help"-> ...
- list的使用命令 百度经验保存
在key对应的list的头部添加字符串元素 命令:lpush #参数0 到-1 是从开始到结束 2 在key对应list的尾部添加字符串元素: 命令:rpush 3 在k ...