日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 3681 Prison Break(状态压缩 + 最短路)

發布時間:2023/12/8 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 3681 Prison Break(状态压缩 + 最短路) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目大意:有一個機器人想越獄,越獄的要求是將所有的電網開關關掉。現在給出一個地圖,’S’表示空地,‘F‘表示起始地點,‘G‘表示充電池,‘D‘表示禁地,‘Y‘開關
充電池可以將機器人的電充滿。機器人每走一格就需要耗掉1點能量,問機器人的起始能量至少要是多少才可以逃出監獄

解題思路:先將所有能連通的點連通起來,將充電池和開關抽象出來,壓縮成一個狀態
求出每個充電池和開關之間的兩兩間的最短距離,接著二分枚舉機器人的初始電量,再暴力枚舉機器人行動的每種情況(dfs)

這里已經求出了充電池和開關之間的最短距離了,那怎樣判斷經過了充電池是否要充電呢
因為枚舉的時候,是只枚舉機器人到充電池和開關的最短路徑的,如果中途遇到了充電池,也就是說最短路的路途中有充電池,這種情況經過是不進行充電的
而如果是枚舉的下一點是充電池的話,這種情況是直接充電的
這樣就把經過充電池該不該充電的情況給考慮進去了

#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; #define N 20 #define M 410 #define S 2010char g[N][N]; int head[M], u[S], v[S], Next[S], id[N][N], dis[N][N], x[N], y[N]; int n, m, num, cnt, final;void add_edgs(int s, int e) {u[cnt] = s;v[cnt] = e;Next[cnt] = head[s];head[s] = cnt++; }void init() {memset(head, -1, sizeof(head));memset(id, -1, sizeof(id));memset(dis, -1, sizeof(dis));cnt = 0; num = 1; final = 0;for (int i = 0; i < n; i++)scanf("%s", g[i]);for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (g[i][j] == 'D')continue;else if (g[i][j] == 'F') {x[0] = i;y[0] = j;id[i][j] = 0;}else if (g[i][j] == 'G') {x[num] = i;y[num] = j;id[i][j] = num++;}else if (g[i][j] == 'Y') {x[num] = i;y[num] = j;final |= (1 << num);id[i][j] = num++;}if (i > 0 && g[i - 1][j] != 'D')add_edgs(i * m + j, (i - 1) * m + j);if (j > 0 && g[i][j - 1] != 'D')add_edgs(i * m + j, i * m + j - 1);if (i + 1 < n && g[i + 1][j] != 'D')add_edgs(i * m + j, (i + 1)* m + j);if (j + 1 < m && g[i][j + 1] != 'D')add_edgs(i * m + j, i * m + j + 1);}} } struct Node {int pos, dis; }n1, n2;bool vis[M]; void bfs(int s) {queue<struct Node> q;memset(vis, 0, sizeof(vis));n1.pos = s;n1.dis = 0;q.push(n1);vis[s] = 1;while (!q.empty()) {n2 = q.front();q.pop();int t = n2.pos;if (id[t / m][t % m] != -1)dis[id[t / m][t % m]][id[s / m][s % m]] = n2.dis;for (int i = head[t]; i != -1; i = Next[i]) {if (vis[v[i]])continue;n1.pos = v[i];n1.dis = n2.dis + 1;q.push(n1);vis[v[i]] = 1;}} }bool mark[N]; bool dfs(int pos, int state, int power, int all_power) {if ((state & final) == final)return true;for (int i = 1; i < num; i++) {if (mark[i] || dis[pos][i] == -1)continue;if (power >= dis[pos][i]) {if (g[x[i]][y[i]] == 'G') {mark[i] = 1;if (dfs(i, state | (1 << i), all_power, all_power))return true;mark[i] = 0;}else {mark[i] = 1;if (dfs(i, state | (1 << i), power - dis[pos][i], all_power))return true;mark[i] = 0;}}}return false; }void solve() {for (int i = 0; i < num; i++)bfs(x[i] * m + y[i]);bool flag = false;int ans = -1;for (int i = 1; i < num; i++)if (g[x[i]][y[i]] == 'Y' && dis[id[x[i]][y[i]]][0] == -1) {flag = true;break;}if (!flag) {int l = 0, r = n * m * (num - 1);while (l <= r) {int mid = (l + r) / 2;memset(mark, 0, sizeof(mark));mark[0] = 1;if (dfs(0, 1, mid, mid)) {ans = mid;r = mid - 1;}else {l = mid + 1;}}}printf("%d\n", ans); }int main() {while (scanf("%d%d", &n, &m) != EOF && n + m) {init();solve();}return 0; }

總結

以上是生活随笔為你收集整理的HDU - 3681 Prison Break(状态压缩 + 最短路)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。