zoukankan      html  css  js  c++  java
  • 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
    ", l);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Taro api封装
    taro中如何定义全局变量
    移动端悬浮框可移动,可回弹,Vue and React
    VS2015 安装mvc4安装包以及vs2010 sp1后导致Razor语法失效代码不高亮(能正常运行)/视图页面无法智能提示(.cshtml)解决办法
    C#6.0新特性的尝试
    Visual Studio Code 添加设置代码段(snippet)
    AngularJs的$http发送POST请求,php无法接收Post的数据解决方案
    [Asp.net mvc] 在Asp.net mvc 中使用MiniProfiler
    [Asp.net mvc]实体更新异常:存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。
    win8.1右键新建菜单添加新建php文件
  • 原文地址:https://www.cnblogs.com/wenruo/p/5165785.html
Copyright © 2011-2022 走看看