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 }