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,它们的公 ...
随机推荐
- PHP配置,php.ini以及覆盖问题
在部署一个cms项目到服务器上的时候,因为cms的模板比较老,服务器上用的php是5.3.3版(大于5.3,可以认为是新的),有些页面会显示"deprecated"类别的错误信息. ...
- BZOJ-1433 假期的宿舍 最大流+基础建图
网络流练习ing.. 1433: [ZJOI2009]假期的宿舍 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1748 Solved: 765 [S ...
- BZOJ-1002 轮状病毒 高精度加减+Kirchhoff矩阵数定理+递推
1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3543 Solved: 1953 [Submit][Statu ...
- POJ3579 Median
Description Given N numbers, X1, X2, ... , XN, let us calculate the difference of every pair of numb ...
- HDU1907 John
Description Little John is playing very funny game with his younger brother. There is one big box fi ...
- Mac OS下编写对拍程序
介绍 对拍是信息学竞赛中重要的技巧,它通过一个效率低下但正确率可以保证的程序,利用庞大的随机生成数据来验证我们的高级算法程序.对拍最大的优势在于可以通过人力所不能及的速度和数量达到验证的效果.下面我们 ...
- threading使用心得
需求:监控多个重要网站(多线程),出现访问异常重试2次,第三次开始告警. 日志模块 import logging import logging.config # 日志配置 LOGCONF_FILENA ...
- std::function,std::bind
std::function 和 std::bind 标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数.bind()接受一个函数(或者 ...
- ios 随机色 宏定义
#define RGBColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #d ...
- C语言strchr()函数:查找某字符在字符串中首次出现的位置
头文件:#include <string.h> strchr() 用来查找某字符在字符串中首次出现的位置,其原型为: char * strchr (const char *str, ...