hdu3681 Prison Break (dfs+二分+状态压缩)

来源:互联网 发布:手机本地端口1080 编辑:程序博客网 时间:2024/06/07 22:20

题意:一个机器人一开始在F,D表示障碍,Y表示开关,G表示充电器。

机器人每走一步消耗一点能量,走到充电器可以瞬间充满电(每个充电器只能充一次),现在要打开所有的开关(每个开关也只用打开一次),问最少的初始电量。


首先计算出所有的G和Y两两之间的最短路,然后二分答案,用dfs判断是否能走完。


代码里有注释:

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <queue>#include <vector>#define INF 0x3f3f3f3fusing namespace std;struct Point{int x, y;Point() {}Point(int a, int b) : x(a), y(b) {}};struct Node{int v, step;Node(int a, int b) : v(a), step(b) {}};int V;// 所有的G和Y的总数int swit;// 所有开关的,压缩到一个int里int n, m;char arr[22][22];Point points[22];//第i个节点的坐标int id[22][22];// 坐标为(i,j)的节点的编号vector<int> edges[333];void addEdge(int from, int to) {edges[from].push_back(to);}// 根据离散化后的坐标返回节点的编号int getID(int v) {return id[v / m][v % m];}int dist[22][22];void spfa(int s) {int sid = getID(s);for (int i = 0; i <= V; i++)dist[sid][i] = INF;dist[sid][sid] = 0;Node now = Node(s, 0);int done[333];memset(done, 0, sizeof(done));done[s] = 1;queue<Node> q;q.push(now);while (!q.empty()) {Node current = q.front();q.pop();int cid = getID(current.v);if (cid != -1) dist[sid][cid] = current.step;for (int i = 0; i < edges[current.v].size(); i++) {int v = edges[current.v][i];if (!done[v]) {done[v] = 1;q.push(Node(v, current.step + 1));}}}}void createGraph() {for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (arr[i][j] == 'D') continue;if (arr[i][j] == 'F') {points[0] = Point(i, j);id[i][j] = 0;}if (arr[i][j] == 'G') {points[V] = Point(i, j);id[i][j] = V++;}if (arr[i][j] == 'Y') {points[V] = Point(i, j);id[i][j] = V;swit |= (1 << V++);}// 离散化坐标,每个点与四周能连的连边if (i > 0 && arr[i - 1][j] != 'D')addEdge(i * m + j, (i - 1) * m + j);if (i < n - 1 && arr[i + 1][j] != 'D')addEdge(i * m + j, (i + 1) * m + j);if (j > 0 && arr[i][j - 1] != 'D')addEdge(i * m + j, i * m + j - 1);if (j < m - 1 && arr[i][j + 1] != 'D')addEdge(i * m + j, i * m + j + 1);}}}int vis[22];int mid;  // 二分的初始电量bool dfs(int v, int energy, int stat) {if ((stat & swit) == swit) return true;// 遍历了所有的开关for (int i = 0; i < V; i++) {if (vis[i] || dist[v][i] == -1 || energy < dist[v][i]) continue;vis[i] = 1;if (arr[points[i].x][points[i].y] == 'G') {// 有充电器的话下一次的电量就是初始电量if (dfs(i, mid, stat | (1 << i))) return true;} else {// 否则消耗一定的电if (dfs(i, energy - dist[v][i], stat | (1 << i))) return true;}vis[i] = 0;}return false;}int getAns() {int l = 0, r = 222222;int ans;// 二分答案while (l <= r) {mid = l + r >> 1;memset(vis, 0, sizeof(vis));vis[0] = 1;if (dfs(0, mid, 1)) {ans = mid;r = mid - 1;} else l = mid + 1;}return ans;}int main() {while (~scanf("%d %d", &n, &m) && n && m) {memset(arr, 0, sizeof(arr));memset(points, 0, sizeof(points));memset(id, -1, sizeof(id));for (int i = 0; i <= n * m; i++) edges[i].clear();V = 1;swit = 0;for (int i = 0; i < n; i++)scanf("%s", arr[i]);createGraph();// 球两两之间最短路for (int i = 0; i < V; i++) {spfa(points[i].x * m + points[i].y);}bool flag = false;for (int i = 1; i < V; i++) {// 如果有Y无法到达就输出-1if (arr[points[i].x][points[i].y] == 'Y' && dist[0][i] == INF) {printf("-1\n");flag = true;break;}}if (flag) continue;int ans = getAns();cout << ans << endl;}return 0;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天猫买的东西发票怎么办 齐鲁医院没床位怎么办 房地产违约交房怎么办 中介收了钱不退怎么办 云联惠被骗的钱怎么办 云联惠被骗的人怎么办 婴儿肚脐凸出来怎么办 捷达伙伴电子扇老转怎么办 云支付买车怎么办 微信商城被骗怎么办 被恒宇商品骗了怎么办 广发二审被拒怎么办 商家一直不发货怎么办 商家迟迟不发货怎么办 鞋子饰品掉了怎么办 京东e卡卡密丢失怎么办 遇到找零钱骗局怎么办 遇到惠凯骗局怎么办? vs2017多个函数怎么办 爱钱进倒闭了钱怎么办 被骗注册了公司怎么办 吃了转基因食物怎么办 微信无法付款怎么办 oppo手机黑屏打不开怎么办 三星手机黑屏打不开怎么办 拼多多发错货了怎么办 提示付款待签收怎么办 别人寄错东西怎么办 买东西被税了怎么办 中国邮政被税了怎么办 眼皮对眼影过敏怎么办 眼影过敏眼睛肿怎么办 澳洲打黑工寄钱怎么办 linux系统忘记密码怎么办 gofun客服打不通怎么办 中信客服打不通怎么办 视频压缩失败无法发送怎么办 ftp文件夹形式打不开怎么办 下载文件删不了怎么办 手机无法加载图片怎么办 cad安装闪退怎么办