【UVa10606】Mines For Diamonds 题解(bfs+枚举)

传送门:https://uva.onlinejudge.org/external/106/10605.pdf



题目大意:给你一个N * M的矩阵,一些格子中分布着钻石(地雷),需要找到若干条不分岔的从边界开始延伸的道路,可以覆盖所有的钻石。求这些道路覆盖的最小方格数。下图中的答案为11。



看到题首先想到用bfs预处理出每对钻石之间的距离以及每个钻石到边界的最短距离,这个可以由对每个钻石bfs求出。

接下来枚举钻石的排列,枚举出来排列之后就可以贪心扫一遍了。具体来说,依次考虑每个钻石,对于一个钻石既可以选择连向后一个,也可以选择不连成为这条链的终点,然后下一个钻石再向墙连边。这两种决策贪心取最小即可。时间复杂度O(N!*N),可以接受。

(其实这个算法有个漏洞:无法防止路径交叉的情况出现。然而我并不能证明路径交叉的情况一定不是最小值,只能脑补一下了……)

这样的话貌似建个图跑个最短路也能过……吗?



请勿吐槽变量名……

代码(299msAC):

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <cctype>
  6 #include <cassert>
  7 #include <ctime>
  8 #include <algorithm>
  9 #include <utility>
 10 #include <functional>
 11
 12 #define X first
 13 #define Y second
 14 #define MP make_pair
 15 #define BP push_back
 16 #define SZ(x) ((int)(x).size())
 17 #define ALL(x) (x).begin(), (x).end()
 18 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
 19
 20 using namespace std;
 21
 22 typedef long long LL;
 23 typedef pair<int, int> Pii;
 24
 25 const int oo = 0x3f3f3f3f;
 26
 27 template<class T> T read(T &x)
 28 {
 29     T f = 1;
 30     char ch = getchar();
 31     while (!isdigit(ch)) {
 32         if (ch == ‘-‘)
 33             f = -1;
 34         ch = getchar();
 35     }
 36     for (x = 0; isdigit(ch); ch = getchar())
 37         x = 10 * x + ch - ‘0‘;
 38
 39     return x *= f;
 40 }
 41
 42 const int MAXN = 15, FUCKER_SIZE = 15;
 43 const int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1};
 44
 45 int N, M;
 46 int A[MAXN][MAXN];
 47 int totFucker;
 48 Pii fucker[FUCKER_SIZE];
 49
 50 int dist[FUCKER_SIZE][FUCKER_SIZE];
 51
 52 void bfs(int s)
 53 {
 54     static int dis[MAXN][MAXN];
 55     static Pii q[MAXN*MAXN];
 56     int front = 0, rear = 0;
 57     memset(dis, 0, sizeof(dis));
 58     q[rear++] = fucker[s];
 59     dis[fucker[s].X][fucker[s].Y] = 1;
 60     while (front != rear) {
 61         Pii u = q[front++];
 62         for (int i = 0; i < 4; i++) {
 63             Pii v(u.X + dx[i], u.Y + dy[i]);
 64             if (v.X == 0 || v.Y == 0 || v.X > N || v.Y > M || dis[v.X][v.Y])
 65                 continue;
 66
 67             dis[v.X][v.Y] = dis[u.X][u.Y] + 1;
 68             if (A[v.X][v.Y] == 0) {
 69                 if (dist[s][0] == 0)
 70                     dist[s][0] = dis[v.X][v.Y] - 1;
 71             } else {
 72                     q[rear++] = v;
 73                     if (A[v.X][v.Y] > 1)
 74                         dist[s][A[v.X][v.Y]-1] = dis[v.X][v.Y] - 1;
 75             }
 76         }
 77     }
 78 }
 79
 80 int main()
 81 {
 82 #ifndef ONLINE_JUDGE
 83     freopen("tmp.in" ,"r", stdin);
 84     freopen("tmp.out", "w", stdout);
 85 #endif // ONLINE_JUDGE
 86     int T;
 87     read(T);
 88     while (T--) {
 89         read(N); read(M);
 90         totFucker = 0;
 91         for (int i = 1; i <= N; i++) {
 92             static char inp[MAXN];
 93             scanf("%s", inp);
 94             for (int j = 1; j <= M; j++) {
 95                 if (inp[j-1] == ‘#‘)
 96                     A[i][j] = 0;
 97                 else if (inp[j-1] == ‘.‘)
 98                     A[i][j] = 1;
 99                 else {
100                     A[i][j] = 1 + (++totFucker);
101                     fucker[totFucker] = MP(i, j);
102                 }
103             }
104         }
105
106         for (int i = 1; i <= totFucker; i++) {
107             memset(dist[i], 0, sizeof(dist[i]));
108             bfs(i);
109         }
110
111         static int p[FUCKER_SIZE];
112         int ans = 0;
113         for (int i = 1; i <= totFucker; i++) {
114             ans += dist[i][0];
115             p[i] = i;
116         }
117         do {
118             int res = dist[p[1]][0];
119             for (int i = 1; i < totFucker; i++) {
120                 res += min(dist[p[i]][p[i+1]], dist[p[i+1]][0]);
121                 if (res + totFucker - i - 1 > ans) {
122                     res = oo;
123                     break;
124                 }
125             }
126             ans = min(ans, res);
127         } while (next_permutation(p + 1, p + 1 + totFucker));
128
129         printf("%d\n", ans);
130
131     }
132
133     return 0;
134 }
时间: 2024-08-07 04:07:19

【UVa10606】Mines For Diamonds 题解(bfs+枚举)的相关文章

BZOJ 1054题解 BFS暴力求解

BZOJ 1054题解 BFS暴力求解 1054: [HAOI2008]移动玩具 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1884  Solved: 1033[Submit][Status][Discuss] Description 在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动 时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移 动到某人

hdu 4400 Mines(离散化+bfs+枚举)

Problem Description Terrorists put some mines in a crowded square recently. The police evacuate all people in time before any mine explodes. Now the police want all the mines be ignited. The police will take many operations to do the job. In each ope

HDU2821Pusher(BFS+枚举)

Pusher Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/65536 K (Java/Others) Total Submission(s): 903    Accepted Submission(s): 327 Special Judge Problem Description PusherBoy is an online game http://www.hacker.org/push . There is an

UVA10603Fill题解--BFS

题目链接 https://cn.vjudge.net/problem/UVA-10603 分析 经典的倒水问题,直接BFS. 对于喜闻乐见的状态判重,一开始想来个哈希函数把一个三元组映射成一个数,后面发现数据很小直接三维数组,后面又发现总水量是固定值,直接二维\(bool\)数组就好了 然后每次取出状态更新下答案,搜索时就是枚举将哪个杯子的水倒入哪个杯子还是很好写的,记得要状态还原 忽然发现最近只会写写水题过活了 代码 #include <cstdio> #include <cstrin

poj 1753 Flip Game (bfs + 枚举)

链接:poj 1753 题意:这是翻棋游戏,给定4*4棋盘,棋子一面为黑色(用b表示),另一面为白色(用w表示),问至少要几步可以将棋子翻为全黑或者全白,如不能达到目的,输出"Impossible " 翻转规则:可以选定16个棋子中的任意一个,将其本身以及上下左右相邻的翻转过来 分析:其实每格棋子最多只可以翻转一次(实际是奇数次,但与翻转一次状态一样),只要其中一格重复翻了2次(不论是连续翻动还是不连翻动),那么它以及周边的棋子和没翻动时的状态是一致的,与最初状态未翻转一样,由此就可以

[题解] [BFS] POJ 1426 - Find The Multiple

p { margin-bottom: 0.25cm; line-height: 115% } a:link { } VJudge题目:https://cn.vjudge.net/contest/279018#problem/L 即POJ 1426 - Find The Multiple:http://poj.org/problem?id=1426 题目要求: 给出一个不大于200的整数n,要求找到任意一个n的倍数(十进制),并且这个倍数只由1与0组成,最多100位. 输入输出:输入以0结束. 示

2016程设期末伪题解

期末发挥实在是太差了-_-# 比2015年少了好多送分题,整体难度显得很大,但是考完之后静下来做又觉得并不是很难orz 1. 篮球联赛:暴力枚举(我用的dfs来枚举) 2. 夺宝探险:暴力dfs 3. 寻找边缘:从边缘暴力dfs 4. 猴子摘桃:可以直接用两个指针指向区间端点做到O(n) 5. 分形盒:直接递归 6. 42点:暴力dfs遍历所有结果 以上几题就不放代码了 7. 上机:dp 题意:有 n 个座位排成一排(1<=n<=10000),给定坐到每个座位上两边有0个.1个和2个人时可获得

poj 1066 题解

题意:求从正方体外面到达这个黑点所需穿过的最少线段数(规定只能从线段中点穿过,包括最外层的墙),共有n面墙 0 <= n <= 30 题解:事实上枚举边界上的中点,判断它和黑点的线段与这些墙的交点数即可 解释:注意到,墙这一长线段相对于黑点连线,等价于直线--无论是在实现上还是题意上.连线若与墙相交,则黑点与枚举点必在墙两侧,无可避免地要穿过这面墙,至于从线段中点穿过在本题中是没有意义的.起始点选取本该在线段中点,但显然选取两个端点的最小值不会比它差,而一个端点的结果不会比相邻的两个中点结果好

【醒目】【业界偷懒】【Public】BZOJ题目一句话题解整理

就当是复习一下自己做过的题,顺便提供一个简要题解给大家看. 做题时候实在想不出来看一下一句话题解,可以有一个提示的作用又不至于一下子知道了全部浪费了一道题吧.. 部分题目(如我A过得大部分奶牛题)是别人拿我的账号做的,不提供题解. 可能会漏掉很多做过的题..因为可能点页数不小心点错了什么的 UPD.本来想把那些没写过但是知道题解的也写了..但是写完这些已经累死了QAQ 已AC的题目(数学题均不提供分析过程,公式): 1000:A+B 1001:平面图最小割,转对偶图最短路 1002:矩阵树定理,