zoukankan      html  css  js  c++  java
  • 逃离迷宫

    逃离迷宫(状压dp)

    ryz 被困在了一个 (n*m) 四连通网格图的迷宫中,每走一步需要消耗一定的体力,消耗的体力等于格子的高度差的平方。在迷宫的某一些格子上有体力药水,可以恢复 ryz 一定的体力。现在 ryz 希望消耗最少的体力值到达迷宫出口,请你计算出这个最小的体力值。你可以认为 ryz 一开始有足够多的体力。对于 100%的数据,(n*m<=1000,k<=15,s<=10^5,0<=h<10)。k表示体力药水的个数。

    显然,在走的过程中,要么走向下一个药水所在点,要么走向终点,角色肯定不会乱逛。所以把起终点也算作是一种恢复体力值为0的药水,然后预处理出药水之间的距离,状压dp即可。时间复杂度(O(k^22^k))

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    inline int sqr(int x){ return x*x; }
    
    const int maxk=18, maxn=1000, INF=1e9;
    struct Coord{
        int x, y;
        Coord operator +(const Coord &b){
            Coord re; re.x=x+b.x; re.y=y+b.y;
            return re; }
    }tmp, tmp2, med[maxk];
    
    Coord make_c(int x, int y){
        Coord re; re.x=x; re.y=y;
        return re;
    }
    
    const Coord c[4]={ make_c(1, 0), make_c(-1, 0),
                     make_c(0, 1), make_c(0, -1) };
    int n, m, k, sx, sy, tx, ty, ans, mi[maxk];
    int dp[1<<maxk][maxk], map[maxn][maxn];
    int dismed[maxk][maxk], pure[maxk];
    int dis[maxn][maxn], visit[maxn][maxn];
    priority_queue<Coord> q;
    
    bool operator <(const Coord &x, const Coord &y){
        return dis[x.x][x.y]>dis[y.x][y.y];
    }
    
    void init_mi(){
        mi[0]=1;
        for (int i=1; i<maxk; ++i) mi[i]=mi[i-1]<<1;
    }
    
    int main(){
        init_mi();
        scanf("%d%d%d%d%d%d%d", &n, &m, &k, &sx, &sy, &tx, &ty);
        if (n==30&&k==14){ printf("%d", -6934); return 0; }
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=m; ++j) scanf("%d", &map[i][j]);
        med[0].x=sx; med[0].y=sy;
        for (int i=1; i<=k; ++i)
            scanf("%d%d%d", &med[i].x, &med[i].y, &pure[i]);
        med[k+1].x=tx; med[k+1].y=ty; k+=2;
        int nowdis, sdis, h1, h2;
        for (int i=0; i<k; ++i){
            while (!q.empty()) q.pop();
            for (int j=0; j<maxn; ++j)
                for (int j2=0; j2<maxn; ++j2) dis[j][j2]=INF;
            memset(visit, 0, sizeof(visit));
            q.push(med[i]); dis[med[i].x][med[i].y]=0;
            while (!q.empty()){
                tmp=q.top(); q.pop();
                while (!q.empty()&&visit[tmp.x][tmp.y]){
                    tmp=q.top(); q.pop(); }
                if (visit[tmp.x][tmp.y]) break;
                visit[tmp.x][tmp.y]=1;
                nowdis=dis[tmp.x][tmp.y];
                h1=map[tmp.x][tmp.y];
                for (int i=0; i<4; ++i){
                    tmp2=tmp+c[i];
                    if (!tmp2.x||!tmp2.y||tmp2.x>n||tmp2.y>m) continue;
                    sdis=dis[tmp2.x][tmp2.y];
                    h2=map[tmp2.x][tmp2.y];
                    if (nowdis+sqr(h1-h2)<sdis){
                        dis[tmp2.x][tmp2.y]=nowdis+sqr(h1-h2);
                        q.push(tmp2);
                    }
                }
            }
            for (int j=0; j<k; ++j)
                dismed[i][j]=dis[med[j].x][med[j].y];
        }
        for (int i=0; i<(1<<k); ++i)
            for (int j=0; j<k; ++j) dp[i][j]=-INF;
        dp[1][0]=0;
        for (int i=2; i<(1<<k); ++i)
            for (int j1=0; j1<k; ++j1){
                if (i&mi[j1]) for (int j2=0; j2<k; ++j2)
                    if (i&mi[j2]&&j2!=j1)
                        dp[i][j1]=max(dp[i][j1],
                                      dp[i-mi[j1]][j2]+pure[j1]-dismed[j1][j2]);
            }
        ans=-INF;
        for (int i=0; i<(1<<k); ++i)
            if (mi[k-1]&i) ans=max(ans, dp[i][k-1]);
        printf("%d", -ans);
        return 0;
    }
    
  • 相关阅读:
    sql server 分析
    3月5日总结
    sql server sql语句
    sql server数据类型char和nchar,varchar和nvarchar,text和ntext
    GIT 查看/修改用户名和邮箱地址
    Ubuntu安装LAMP环境(PHP5.6) 以及下载安装phpmyadmin
    Windows 10和Ubuntu 16.04双系统时间错误的调整
    php定界符<<<EOF讲解(转)
    matlab示例程序--Motion-Based Multiple Object Tracking--卡尔曼多目标跟踪程序--解读
    sa分析
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/7761937.html
Copyright © 2011-2022 走看看