zoukankan      html  css  js  c++  java
  • b_vj_Hunter(dij预处理宝藏与宝藏外界的最短距离+状压dp)

    有一个n*m的网格,正数格子代表被研究的费用,-1代表不能被研究,且网格中有k个宝藏;问一个宝藏猎人以网格外部为起点进入网格,并收集所有宝藏回到起点的最小花费。(1<=K<=13,n,m<=200)

    思路:f[i][j]表示终点在宝藏i,且宝藏状态为j时的最少花费;
    由于要回到起点,所以在dijkstra中用out[id]表示从i走到边界的最短距离

    #include<iostream>
    #include<math.h>
    #include<queue>
    using namespace std;
    const int N=205, M=20, inf=0x3f3f3f3f, dir[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };
    int n,m,K,d[N][N],sp[N][N],g[N][N],out[N],f[M][1<<M];
    struct node {
        int x,y,w;
    }T[N];
    struct cmp{
        bool operator()(node& a, node& b){
            return a.w > b.w;
        }
    };
    void dij(int sx, int sy, int id) {
        for (int i=0; i<n; i++) for (int j=0; j<m; j++) sp[i][j]=inf;
        priority_queue<node, vector<node>, cmp> q;
        q.push({sx,sy,0}), sp[sx][sy]=0;
        while (!q.empty()) {
            int x=q.top().x, y=q.top().y; q.pop();
            if (x==0 || x==n-1 || y==0 || y==m-1)  //宝藏到边界的距离,注g[sx][sy]的花费没有尚未算进去
                out[id]=min(out[id], sp[x][y]);
            for (int k=0; k<4; k++) {
                int tx=x+dir[k][0], ty=y+dir[k][1];
                if (tx>=0 && tx<n && ty>=0 && ty<m && g[tx][ty]!=-1 && sp[tx][ty]>sp[x][y]+g[tx][ty]) {
                    sp[tx][ty]=sp[x][y]+g[tx][ty];
                    q.push({tx,ty,sp[tx][ty]});
                }
            }
        }
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int q; cin>>q;
        while (q--) {
            cin>>n>>m;
            for (int i=0; i<n; i++)
            for (int j=0; j<m; j++)
                cin>>g[i][j];
            cin>>K;
            for (int i=0; i<K; i++) cin>>T[i].x>>T[i].y;
            //求出宝藏与宝藏之间的最短距离(注:dij只能求单源最短路)
            for (int i=0; i<K; i++) {
                out[i]=inf; //out[i]就是宝藏到外界的最短距离
                dij(T[i].x,T[i].y,i);
                for (int j=0; j<K; j++) {
                    d[i][j]=sp[T[j].x][T[j].y];
                }
            }
            int tot=1<<K, ans=inf;
            for (int i=0; i<K; i++) for (int j=0; j<tot; j++) f[i][j]=inf;
            for (int i=0; i<K; i++) f[i][1<<i]=g[T[i].x][T[i].y]+out[i]; //外界到宝藏i的距离
            
            for (int j=0; j<tot; j++)
            for (int s=0; s<K; s++) if (j&(1<<s) && f[s][j]!=inf) {
                for (int e=0; e<K; e++) if ((j&(1<<e))==0) 
                    f[e][j|(1<<e)]=min(f[e][j|(1<<e)], f[s][j]+d[s][e]);
            }
            for (int i=0; i<K; i++) ans=min(ans, f[i][tot-1]+out[i]); //终点在i,且从i出去
            cout<<ans<<'
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    Perl 正则匹配经验记录
    Linux——高效玩转命令行
    推荐一个SAM文件或者bam文件中flag含义解释工具
    单端测序(Single- ead)和双端测序(Pai ed-end和Mate-pai )的关系
    区别samtools faid产生的.fai文件功能和bwa index 产生的四个文件的功能
    Perl新接触的小命令
    Perl调用外部命令(其他脚本、系统命令)的方法和区别
    Linux——命令
    学习《Python金融实战》中文版PDF+英文版PDF+源代码
    学习《深度学习与计算机视觉算法原理框架应用》《大数据架构详解从数据获取到深度学习》PDF代码
  • 原文地址:https://www.cnblogs.com/wdt1/p/13940843.html
Copyright © 2011-2022 走看看