zoukankan      html  css  js  c++  java
  • HDU 4568 Hunter 最短路+状压DP

    题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝藏的最小花费,如果一次不能拿走所有能拿到的或者根本拿不到任何宝藏,输出0.

    解法:看到k的范围应该想到状态压缩,将每个格子都看成一个点,再新建两个点,一个表示边界外的起点,用0表示,一个表示边界外的终点,用n*m+1表示,然后相互建边,建有向边,边权为终点格子的花费值,(其实都不用建边,直接跑最短路也行)然后求这k+2个点两两之间的最短距离,然后就化成TSP问题了,用状压DP可以解决。

    求k+2个点两两之间的最短距离可以跑k+2次SPFA求出,复杂度不高。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <queue>
    #include <algorithm>
    #define Mod 1000000007
    using namespace std;
    #define N 10007
    
    int mp[304][304];
    int C[304][304];
    int dis[20][20];
    int n,m,k;
    int d[50005];
    struct node
    {
        int v,w,next;
    }G[4*50005];
    int head[4*50005],tot;
    int dx[4] = {0,0,1,-1};
    int dy[4] = {1,-1,0,0};
    int vis[50006];
    struct Point
    {
        int x,y;
    }P[15];
    
    int OK(int nx,int ny)
    {
        if(nx >= 1 && nx <= n && ny >= 1 && ny <= m)
            return 1;
        return 0;
    }
    
    void addedge(int u,int v,int w)
    {
        G[tot].v = v;
        G[tot].w = w;
        G[tot].next = head[u];
        head[u] = tot++;
    }
    
    void SPFA(int s)
    {
        queue<int> que;
        memset(vis,0,sizeof(vis));
        que.push(s);
        for(int i=0;i<=n*m+1;i++) d[i] = Mod;
        d[s] = 0, vis[s] = 1;
        while(!que.empty())
        {
            int u = que.front();
            que.pop();
            vis[u] = 0;
            for(int i=head[u];i!=-1;i=G[i].next)
            {
                int v = G[i].v;
                int w = G[i].w;
                if(d[v] > d[u] + w)
                {
                    d[v] = d[u] + w;
                    if(!vis[v])
                        vis[v] = 1,que.push(v);
                }
            }
        }
    }
    
    int dp[1<<17][20];
    
    int main()
    {
        int i,j;
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            for(i=1;i<=n;i++)
                for(j=1;j<=m;j++)
                {
                    scanf("%d",&C[i][j]);
                    if(C[i][j] == -1)
                        C[i][j] = Mod;
                }
            memset(head,-1,sizeof(head));
            tot = 0;
            for(i=1;i<=n;i++)
            {
                for(j=1;j<=m;j++)
                {
                    int now = (i-1)*m + j;
                    for(int h=0;h<4;h++)
                    {
                        int kx = i + dx[h];
                        int ky = j + dy[h];
                        if(!OK(kx,ky))
                            continue;
                        int tmp = (kx-1)*m + ky;
                        addedge(now,tmp,C[kx][ky]);
                    }
                    if(i == 1 || i == n || j == 1 || j == m)  //边界
                    {
                        addedge(0,now,C[i][j]);
                        addedge(now,n*m+1,0);
                    }
                }
            }
            scanf("%d",&k);
            P[0].x = 1, P[0].y = 0;
            P[k+1].x = n,P[k+1].y = m+1;
            for(i=1;i<=k;i++)
                scanf("%d%d",&P[i].x,&P[i].y),P[i].x++,P[i].y++;
            for(i=0;i<=k+1;i++)
            {
                int s = (P[i].x-1)*m + P[i].y;
                SPFA(s);
                for(j=0;j<=k+1;j++)
                {
                    if(i == j) continue;
                    int v = (P[j].x-1)*m + P[j].y;
                    dis[i][j] = d[v];
                }
            }
            for(i=0;i<(1<<16);i++)
                for(j=0;j<16;j++)
                    dp[i][j]=Mod;
            for(i=0;i<k;i++)
                dp[1<<i][i+1]=dis[0][i+1];
            for(i=0;i<(1<<k);i++)
            {
                for(int kk=0;kk<k;kk++)
                {
                    if(!(i&(1<<kk)))continue;
                    for(int j=0;j<k;j++)
                    {
                        if(i&(1<<j)) continue;
                        dp[i+(1<<j)][j+1]=min(dp[i+(1<<j)][j+1],dp[i][kk+1]+dis[kk+1][j+1]);
                    }
                }
            }
            int minn=Mod;
            for(i=1;i<=k;i++)
                minn=min(dp[(1<<k)-1][i]+dis[i][k+1],minn);
            if(minn == Mod)
                cout<<0<<endl;
            else
                cout<<minn<<endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    发布在Xilinx 嵌入式系统中文论坛的旧帖子
    【分享】MPSoC,XEN虚拟机运行裸核应用程序(baremetal, standalone)的中断延迟
    【分享】 在Vivado里关闭R5/GPU,降低Xilinx MPSoC的功耗
    python实现单链表
    Flink 作业问题分析和调优实践
    flink 有状态 udf引发的大坑一
    flink checkpoint 在 window 操作下 全局配置失效的问题
    python实现十大经典排序算法
    Flink on yarn 常见错误
    搭建Spark所遇过的坑
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3962180.html
Copyright © 2011-2022 走看看