hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费。

思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可。

代码如下:

  1 /**************************************************
2 * Author : xiaohao Z
3 * Blog : http://www.cnblogs.com/shu-xiaohao/
4 * Last modified : 2014-05-15 16:59
5 * Filename : C.cpp
6 * Description :
7 * ************************************************/
8
9 #include <iostream>
10 #include <cstdio>
11 #include <cstring>
12 #include <cstdlib>
13 #include <cmath>
14 #include <algorithm>
15 #include <queue>
16 #include <stack>
17 #include <vector>
18 #include <set>
19 #include <map>
20 #define MP(a, b) make_pair(a, b)
21 #define PB(a) push_back(a)
22
23 using namespace std;
24 typedef long long ll;
25 typedef pair<int, int> pii;
26 typedef pair<unsigned int,unsigned int> puu;
27 typedef pair<int, double> pid;
28 typedef pair<ll, int> pli;
29 typedef pair<int, ll> pil;
30
31 const int INF = 0x3f3f3f3f;
32 const double eps = 1E-6;
33 const int LEN = 210;
34 int Map[LEN][LEN], mp[LEN][LEN], out[LEN], in[LEN], dp[1<<13][20];
35 int n, m, vn, N;
36 int xx[] = {0, 0, 1,-1};
37 int yy[] = {1,-1, 0, 0};
38 pii vex[LEN];
39
40 bool J(int x, int y){
41 if(x == 1 || x == n || y == 1 || y == m) return true;
42 return false;
43 }
44
45 bool Ja(int x, int y){
46 if(x>0 && x<=n && y>0 && y<=m) return true;
47 return false;
48 }
49
50 struct P{
51 int x, y, val;
52 bool operator<(const P a) const
53 {
54 return this->val > a.val;
55 }
56 };
57
58 P mmp(int a, int b, int c){
59 P ret;
60 ret.x = a;ret.y = b;ret.val = c;
61 return ret;
62 }
63
64 int Bfs(int sx, int sy, int ex, int ey){
65 int vis[210][210] = {0};
66 priority_queue<P> q;
67 q.push(mmp(sx, sy, 0));
68 vis[sx][sy] = 1;
69 while(!q.empty()){
70 P nv = q.top();q.pop();
71 int x = nv.x, y = nv.y, val = nv.val;
72 if(ex < 0 && ey < 0){
73 if(J(x, y)) return val;
74 }
75 else if(x == ex && y == ey) return val;
76 for(int i=0; i<4; i++){
77 int tx = x + xx[i];
78 int ty = y + yy[i];
79 if(Ja(tx, ty) && !vis[tx][ty]){
80 vis[tx][ty] = 1;
81 q.push(mmp(tx, ty, val + mp[tx][ty]));
82 }
83 }
84 }
85 return -1;
86 }
87
88 void init(){
89 for(int i=0; i<vn; i++){
90 for(int j=0; j<vn; j++){
91 Map[i][j] = Bfs(vex[i].first, vex[i].second, vex[j].first, vex[j].second);
92 }
93 }
94 for(int i=0; i<vn; i++){
95 int x = vex[i].first, y = vex[i].second;
96 out[i] = Bfs(x, y, -1, -1);
97 in[i] = out[i] + mp[x][y];
98 }
99 }
100
101 int dfs(int x, int lv){
102 if(dp[x][lv] != INF) return dp[x][lv];
103 int cnt = 0;
104 for(int i=0; i<vn; i++){
105 if(x & (1 << i)) cnt ++ ;
106 }
107 if(cnt == 1) return dp[x][lv] = in[lv];
108 int ret = INF;
109 for(int i=0; i<vn; i++){
110 if((x & (1<<i)) && i != lv){
111 int &val = Map[i][lv];
112 ret = min(ret, dfs(x^(1<<lv), i) + val);
113 }
114 }
115 return dp[x][lv] = ret;
116 }
117
118 int main()
119 {
120 // freopen("in.txt", "r", stdin);
121
122 int T, a, b;
123 scanf("%d", &T);
124 while(T--){
125 scanf("%d%d", &n, &m);
126 memset(Map, 0x3f, sizeof Map);
127 memset(mp, 0, sizeof mp);
128 memset(dp, 0x3f, sizeof dp);
129 for(int i=1; i<=n; i++){
130 for(int j=1; j<=m; j++){
131 scanf("%d", &mp[i][j]);
132 if(mp[i][j] == -1) mp[i][j] = INF;
133 }
134 }
135 scanf("%d", &vn);
136 for(int i=0; i<vn; i++){
137 scanf("%d%d", &a, &b);
138 a++, b++;
139 vex[i] = MP(a, b);
140 }
141 init();
142 int ans = INF;
143 for(int i=0; i<vn; i++){
144 ans = min(ans, dfs((1<<vn)-1, i) + out[i]);
145 }
146 if(ans != INF) printf("%d\n", ans);
147 else printf("0\n");
148 }
149 return 0;
150 }

hdu 4568(状态压缩dp),布布扣,bubuko.com

时间: 2024-08-24 23:59:58

hdu 4568(状态压缩dp)的相关文章

hdu 5180 状态压缩 dp 打表

hdu 5180 状态压缩 dp 打表 题意: 在n*n的国际象棋中,放置若干个国王和k个车,使得国王之间不互相攻击,车之间不互相攻击,车不可攻击到国王(这并不代表国王不能攻击到车).国王能攻击到它上下左右,左上左下右上右下八个位置的棋子,车可以攻击到同一行或同一列中的棋子,求方案总数对1000000007取模后的值. 限制: 1 <= n <=15; 0 <= k <=15 思路: 状态压缩,dp,打表套打表 打表程序如下: 打表程序1: tab[a][b]表示a*b的棋盘王的放

hdu 4917Permutation(状态压缩DP)

hdu 4917Permutation(状态压缩DP) 题意:将1~n的n个数排列成序列(n<=40),但有m(m<=20)个限制条件,其中第i个限制条件的表示为ai,bi.表示该序列的第ai的数要小于第bi的.问有多少中排列?保证有解 解法:我们首先可以明确一点,这m个限制条件,所表示的关系会构成若干个DAG(有向无环图,我将其称之为拓扑图).我们只要将这n个数,填入到拓扑图上,使其满足拓扑关系,那么这样的序列就是可以的.而这若干个拓扑图之间,是不会相互影响的,因而我们可以单独考虑每一个拓扑

hdu 5135 状态压缩dp

题意是给出最对12条边你     问最大可组成三角形面积是多大 (可有多个三角形)   典型的状态压缩  (最多12条边) 思路: 先暴力枚举所有可能三角形的面积   然后再根据状态压缩来做    最多可组成n/3个三角形  对每个三角形都记录三边或(运算)    和面积    然后判断进行合并  (根据且运算)   就行了 #include<stdio.h> #include<string.h> #include<cmath> #include<iostream

hdu 4284 状态压缩dp

题意: 有N 个点的无向图,要去其中 h个地点做事,做事需要先办理护照,之后可以挣一定数量的钱,知道了一开始有的总钱数,和 一些城市之间           道路的花费,问可不可以在 指定的 h 个城市打完工,并回到起点 1. 链接:点我 是个好题!!! 状态转移方程dp[s][i]=max(dp[s][i],dp[s'][j]-maps[j][i]-d[i]+c[i]); dp[s][i]表示当在状态s的时候最后再i城市打工的最多剩余钱数. 2 4 5 10 //4个点,5个道路,10单位的钱

HDU 4856 (状态压缩DP+TSP)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4856 题目大意:有一个迷宫.迷宫里有些隧道,每个隧道有起点和终点,在隧道里不耗时.出隧道就耗时,你的任务是访问完所有隧道且仅一次,求最短耗时. 解题思路: 暑假练习的时候.把英文读了N遍也没理解题意. 其实就是个最后不回到开头的TSP. 首先求BFS求两两隧道之间的最短路,注意BFS的起点是隧道i的终点,BFS的终点是隧道j的起点. 一定要特判一下两个隧道终点和起点是否一样,如果一样话dis=0,

HDU 5067 (状态压缩DP+TSP)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5067 题目大意:蓝翔挖掘机挖石子.把地图上所有石子都运回起点,问最少耗时. 解题思路: 首先得YY出来. 最少耗时肯定是从起点出发,把所有石子点走一遍且只走一遍,把石子装在车上,然后最后回到起点. 由于石子堆最多也就10个.不难看出这就是个裸的TSP. 首先BFS计算出每个石子间的最短路. 然后进行TSP就行了. 起点的石子无所谓.所以TSP的起点就是(1,1). #include "cstdio

2016&quot;百度之星&quot; - 初赛(Astar Round2A)1002 / HDU 5691 状态压缩DP

Sitting in Line Problem Description 度度熊是他同时代中最伟大的数学家,一切数字都要听命于他.现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了.游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数.度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置. Input 第一行一个整数T,表示T组数

hdu 5103 状态压缩dp

这题说的是给了n(14)个点,每个点都以他 为根的最大可容的孩子个数和最小的可溶孩子个数L[i] ,R[i] 问这n个点形成一棵树有多少种形态 我们让 dp[i][S] 表示 一 i为根节点 的 拥有孩子S(二进制数)状态的 方案数 , sub[S] , 表示 以 S 状态表示的 森林的 方案数, sum[S] 表示 一S 状态的 有根树 的 方案数 可以知道 dp[i][S] = sub[ S^(1<<i) ] { L[i]<=|S|<=R[i]   } sum[S] = dp[

hdu 2167状态压缩dp

和杭电上的取石子这道题差不多就是多了个斜着也不行    其次就是输入格式了 先预处理下   把所有满足一行的所有状态列出来   并把相应的和求出来 然后按照dp相应的思路求 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; int num[20][20]; int mark[1<<16]; int sum[20][1<<16],have[100

HDU 1074 状态压缩DP 第一次写 多多指教

给你n个数表示有n门作业,下面n行  每行三个数 分别为学科名 截止时间  需要多久才能完成 如果逾期一天则扣掉一学分, 要你求出完成所有作业而被扣最小的学分, 并将完成作业的顺序输出.(时间相同时 按照单词字典数输出) 学分相同时按照字典数输出   目前对于从n-1到0不是很理解 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<map