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,它们的公 ...
随机推荐
- getHibernateTemplate()的用法
getHibernateTemplate() spring 中获得由spring所配置的hibernate的操作对象,然后利用此对象进行,保存,修改和删除等操作,此方法是在配置了spring以后,hi ...
- 【bzoj1013】 JSOI2008—球形空间产生器sphere
www.lydsy.com/JudgeOnline/problem.php?id=1013 (题目链接) 题意 有一个n维的球体,给出球上n+1个点,求出圆心. Solution 题中给出了对于n维空 ...
- BZOJ3732 Network
Description 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_ ...
- USACO 3.2 kimbits DP
自己YY了个DP:设f[n][l]为n位数中包含不超过l个1的总个数 f[n][l]=f[n-1][l]+f[n-1][l-1] 然后用_search()从高位向低位扫描即可,tmp记录当前已记下多少 ...
- Linux File、File Directory IO Operation Summary(undone)
目录 . 引言 . Linux下文件操作API . Linux下文件目录操作API . Linux下的其他设备操作API 1. 引言 Linux支持多种文件系统,如ext.ext2.minix.iso ...
- linux中防CC攻击两种实现方法(转)
CC攻击就是说攻击者利用服务器或代理服务器指向被攻击的主机,然后模仿DDOS,和伪装方法网站,这种CC主要是用来攻击页面的,导致系统性能用完而主机挂掉了,下面我们来看linux中防CC攻击方法. 什么 ...
- c++ 类型安全
类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域.“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制:有的时候也用“类型安全”形容 ...
- tp auth 转载保存
PS:最近需要做一个验证用户权限的功能,在官方和百度看了下,发现大家都是用auth来做验证,官方有很多auth的使用教程,但是都不全面,我也提问了几个关于auth的问题 也没人来回答我,无奈只好一步步 ...
- Spring IoC实现解耦合
public class UserDaoImpl implements UserDao{ @Override public void save(User user) { // TODO Auto-ge ...
- jetty使用教程(嵌入eclipse开发)
在eclipse下面建一个java project 建立目录结构如下: 二级目录: (备注jetty_test是工程的根目录,etc.lib.webRoot为其二级目录) 到jetty的官方网站(ht ...