hdu3681--Prison Break(TSP+二分)

好难的一道题。

题意:一个机器人要逃出监狱,每走一步消耗一点电量,初始时电量是满的。给一个n*m(n,m<=15)的字符数组代表监狱,F代表起始点,G代表补充满电量,每个G只能补充一次,Y代表开关,D不能经过,S表示空地。要求打开所有开关,也就是经过所有Y点,电池的满电量最少是多少。如果不能逃出输出-1。G和Y的个数和不会超过15。

题解:二分答案。通过bfs预处理出G,Y,F两两之间的距离,然后转化成TSP求解。借鉴了别人的代码。

#include <bits/stdc++.h>
#define clr(x,c) memset(x,c,sizeof(x))
using namespace std;

struct Point {
    int x, y;
    int d;
    Point(int x, int y, int d) : x(x), y(y), d(d) {}
    Point(int x, int y) : x(x), y(y), d(0) {}
    Point() {}

    bool operator ==(const Point a) const {
        if (x == a.x && y == a.y) return true;
        return false;
    }

} p[50];

int m, n;
char mp[20][20];
int cf;
int dis[20][20];
int cnt = 0;
int ac = 0; // 所有y的集合
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int vis[20][20];
int dp[1<<17][20];

bool ok(int x, int y)
{
    if (x < n && x >= 0 && y < m && y >= 0 &&
        mp[x][y] != ‘D‘ && !vis[x][y])
        return true;
    return false;
}

int bfs(int a, int b)
{
    clr(vis, 0);
    queue<Point> q;
    q.push(p[a]);
    vis[p[a].x][p[a].y] = 1;
    while (!q.empty()) {
        Point now = q.front();
        q.pop();

        if (now == p[b]) return now.d;
        for (int i = 0; i < 4; ++i) {
            int nx = now.x + dir[i][0];
            int ny = now.y + dir[i][1];
            if (!ok(nx, ny)) continue;
            int nd = now.d + 1;
            q.push(Point(nx, ny, nd));
            vis[nx][ny] = 1;
        }
    }
    return -1;
}

void getDis()
{
    for (int i = 0; i < cnt; ++i) {
        for (int j = i; j < cnt; ++j) {
            if (i == j) dis[i][j] = 0;
            else dis[j][i] = dis[i][j] = bfs(i, j);
        }
    }
}

bool canGo(int en)
{
    clr(dp, -1);
    int st = (1 << cnt);
    dp[1 << cf][cf] = en;
    for (int i = 0; i < st; ++i) {
        for (int j = 0; j < cnt; ++j) {
            if ( !((1 << j) & i) || dp[i][j] == -1 ) continue;
            if ((i & ac) == ac) return true;
            for (int k = 0; k < cnt; ++k) {
                if ( (1 << k) & i || dis[j][k] == -1 || dp[i][j] < dis[j][k] ) continue;
                int nt = (1 << k) | i;
                dp[nt][k] = max(dp[nt][k], dp[i][j] - dis[j][k]);
                if (mp[ p[k].x ][ p[k].y ] == ‘G‘) dp[nt][k] = en;
            }
        }
    }
    return false;
}

int main()
{
    while (~scanf("%d%d", &n, &m)) {
        if (n == 0 && m == 0) break;

        for (int i = 0; i < n; ++i)
            scanf("%s", mp[i]);

        ac = cnt = 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (mp[i][j] == ‘F‘) {
                    cf = cnt;
                    ac += (1 << cnt);
                    p[cnt++] = Point(i, j);
                } else if (mp[i][j] == ‘G‘) {
                    p[cnt++] = Point(i, j);
                } else if (mp[i][j] == ‘Y‘) {
                    ac += (1 << cnt);
                    p[cnt++] = Point(i, j);
                }
            }
        }

        getDis();

        int l = 0, r = 300;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (canGo(mid)) r = mid - 1;
            else l = mid + 1;
        }
        if (l >= 300) l = -1;
        printf("%d\n", l);
    }
    return 0;
}

  

时间: 2024-08-29 23:13:24

hdu3681--Prison Break(TSP+二分)的相关文章

HDU3681 Prison Break(状压dp)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

HDU3681(Prison Break)

题目链接:传送门 题目大意:给你一副n*m大小的图,'D'表示墙,'F'表示起点,'S'表示空地,'G'表示能源站,'Y'表示开关,一开始机器人处在'F'并有一个初始能量,每走一步会消耗一格能量 机器人需要在能量耗尽前经过所有'Y'至少一次,其中经过'G'可补满能量回初始值但每个'G'只能补一次,问至少需要几个能量才能达到要求. 题目思路:这个题感觉真的是很考验功底,集bfs,状态压缩DP,二分于一身,且实现细节不能马虎,实在是一道好题. 为什么说是状态压缩DP,You can assume t

HDU 3681 Prison Break(bfs+二分+状压DP)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3778    Accepted Submission(s): 992 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

hdu 3681 Prison Break (状态压缩+bfs+最短路)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3214    Accepted Submission(s): 829 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

hdu 3681 Prison Break(状态压缩+bfs)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

hdu 3511 Prison Break

http://acm.hdu.edu.cn/showproblem.php?pid=3511 题意: 给出n个相离或包含的圆,问最里层的圆是第几层 竖着的扫描线与圆在最左侧相切时 1.线在圆的上方或下方无交点,则该圆在第1层 2.线在圆的上下方都有交点,且上下方的交点属于同一个圆C,则该圆在圆C的里面一层 3.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF其中一个在另一个里面,则该圆与在里面的那个圆处在同一层 4.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF在同一层,则该圆

【状压+二分+BFS】HDU 3681 Prison Break

通道:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意:机器人从F出发,走到G可以充电,D不能走进,走到Y关掉开关,要求把所有开关关掉,且电量最少,并求出初始最小电量. 思路:二分初始的电量,预处理任意G,Y,F之间的最短距离,然后状压dp[s][u]:状态为s的u为起点遍历整个图的最小布数. 代码:https://github.com/Mithril0rd/Rojo/blob/master/hdu3681.cpp TAG:代码来自华仔

HDU 3681 Prison Break floyd+状压+二分

题目链接:点击打开链接 题意: 给定n*m的矩阵: F:起点(有且仅有一个) D:坏点(不能走到这个点) G:能量池(走到这个点可以选择使用这个点的能量池,把电池充满,也可以暂时不用,只能使用一次) Y:目标点 问: 遍历所有Y点需要最小的电池容量是多少. 开始电池满电,每走一步消耗一格电. Y+G的个数<=15. n,m<=15 思路:状压YG,前面几位表示Y,后面几位表示G. 先跑个floyd,然后二分电池容量,状压dp判可行 #include <cstdio> #includ

1254 - Prison Break

  PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Michael Scofield has just broken out of the prison. Now he wants to go to a certain city for his next unfinished job. As you are the only programmer on his gang, he asked yo