Hdu--5067(DP,状态压缩)

2014-10-18 22:57:04

思路:BC #14 的第三题,当时用记忆化搜索过了present然后FST就跪了-。-,原因是考虑了空余点导致费时。正确的姿势是只考虑有石头的点,再配上状压就能妥过,记忆化 / 递推皆可,这里采用简洁的递推。dp[i][j] 表示到达第 i 个石头,且状态为 j 时的最优解,扫一下 j 的每一位,如第 k+1 位是 1,那么说明这个状态可以由k个点转移过来, 建立转移方程:dp[i][j] = min(dp[i][j] , dp[k][j ^ (1 << (i - 1))] + Distance(i , k));

  注意,状态DP的递推方向,是以状态作为主方向(即:放在最外层循环),因为如果要全面考虑,那么认为每个状态都可能由任一点转移过来。

 1 /*************************************************************************
 2     > File Name: 1002.cpp
 3     > Author: Nature
 4     > Mail: 564374850@qq.com
 5     > Created Time: Sat 18 Oct 2014 09:44:23 PM CST
 6 ************************************************************************/
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <cstdlib>
11 #include <cmath>
12 #include <vector>
13 #include <map>
14 #include <set>
15 #include <stack>
16 #include <queue>
17 #include <iostream>
18 #include <algorithm>
19 using namespace std;
20 #define lp (p << 1)
21 #define rp (p << 1|1)
22 #define getmid(l,r) (l + (r - l) / 2)
23 #define MP(a,b) make_pair(a,b)
24 typedef long long ll;
25 const int INF = 1 << 30;
26 
27 int dp[11][(1 << 10) + 10];
28 int x[11],y[11];
29 int n,m,cnt;
30 
31 int main(){
32     int tmp;
33     while(scanf("%d%d",&n,&m) != EOF){
34         cnt = 0;
35         for(int i = 1; i <= n; ++i){
36             for(int j = 1; j <= m; ++j){
37                 scanf("%d",&tmp);
38                 if(tmp){
39                     x[++cnt] = i;
40                     y[cnt] = j;
41                 }
42             }
43         }
44         for(int i = 0; i <= cnt; ++i)
45             for(int j = 0; j < (1 <<cnt); ++j)
46                 dp[i][j] = INF;
47         for(int i = 1; i <= cnt; ++i)
48             dp[i][(1 << (i - 1))] = x[i] + y[i] - 2;
49         for(int j = 0; j < (1 << cnt); ++j)
50             for(int i = 1; i <= cnt; ++i)
51                 for(int k = 1; k <= cnt; ++k)
52                     if(j & (1 << (k - 1)))
53                         dp[i][j] = min(dp[i][j],dp[k][j ^ (1 << (i - 1))] + abs(x[i] - x[k]) + abs(y[i] - y[k]));
54         int ans = cnt == 0 ? 0 : INF;
55         for(int i = 1; i <= cnt; ++i)
56             ans = min(ans,dp[i][(1 << cnt) - 1] + x[i] + y[i] - 2);
57         printf("%d\n",ans);
58     }
59     return 0;
60 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4033999.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值