HDU 4568 旅行商问题

一个N*M的迷宫,每个点有代价,代价为-1时表示不能走到,迷宫中有k个宝藏,求取走所有宝藏所需要的最小代价,只能进入迷宫一次

计算出所有宝藏之间的最短距离及从该宝藏出迷宫的最短距离,然后做状压DP即可

#include "stdio.h"
#include "string.h"
#include "queue"
using namespace std;

struct node
{
    int x,y,cost;
    bool friend operator<(node n1,node n2)
    {
        return n2.cost<n1.cost;
    }
};
const int inf=0x3f3f3f3f;
const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} };
int n,m,k,tot;
int dis[20][20],mark[210][210],a[210][210],b[20],x[20],y[20]; // mark记录点是否存在宝藏并记录编号,dis记录宝藏间最短距离
int used[210][210],dp[70000][20]; // dp[i][j]=i状态,以j点为最终结点的最小代价

int Min(int a,int b)
{
    if (a<b) return a;
    else return b;
}
int judge(int x,int y)
{
    if (x<0 || y<0 || x>=n || y>=m) return 0;
    if (used[x][y]!=0) return 0;
    if (a[x][y]==-1) return 0;
    return 1;
}
void bfs(int w)
{
    priority_queue<node>q;
    node cur,next;
    int i;

    memset(used,0,sizeof(used));
    cur.x=x[w];
    cur.y=y[w];
    cur.cost=0;
    if (cur.x==0 || cur.y==0 || cur.x==n-1 || cur.y==m-1) // 是否在边界,在边界则记录到0号点距离
        dis[w][0]=dis[0][w]=dis[w][k+1]=dis[k+1][w]=0;
    used[cur.x][cur.y]=1;
    q.push(cur);
    while (!q.empty())
    {
        cur=q.top();
        q.pop();
        for (i=0;i<4;i++)
        {
            next.x=cur.x+dir[i][0];
            next.y=cur.y+dir[i][1];
            if (judge(next.x,next.y)==0) continue;

            next.cost=cur.cost+a[next.x][next.y];
            used[next.x][next.y]=1;
            if (next.x==0 || next.y==0 || next.x==n-1 || next.y==m-1)
            {
                dis[w][0]=dis[0][w]=Min(dis[w][0],next.cost);
                dis[w][k+1]=dis[k+1][w]=dis[w][0];
            }

            if (mark[next.x][next.y]!=0)
            {
                dis[w][mark[next.x][next.y]]=Min(dis[w][mark[next.x][next.y]],next.cost-a[next.x][next.y]);
                dis[mark[next.x][next.y]][w]=dis[w][mark[next.x][next.y]];
            }
            q.push(next);
        }
    }
}

void DP()
{
    int i,j,l;
    memset(dp,inf,sizeof(dp));
    dp[1][0]=0;
    for (i=0;i<=tot;i++)
        for (j=0;j<=k+1;j++)
        if ( (b[j]&i)!=0 && dp[i][j]!=-1)
            for (l=0;l<=k+1;l++)
            if (l!=j && (b[l]&i)==0)
                dp[i+b[l]][l]=Min(dp[i+b[l]][l],dp[i][j]+dis[j][l]);

}
int main()
{
    int t,i,j,ans;
    b[0]=1;
    for (i=1;i<=16;i++)
        b[i]=b[i-1]*2;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        for (i=0;i<n;i++)
            for (j=0;j<m;j++)
            scanf("%d",&a[i][j]);
        scanf("%d",&k);
        memset(mark,0,sizeof(mark));
        for (i=1;i<=k;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
            mark[x[i]][y[i]]=i;
        }
        memset(dis,inf,sizeof(dis));
        for (i=1;i<=k;i++)
            bfs(i); // 计算所有宝藏间的最短距离及与边界的最短距离
        tot=b[k+2]-1;
        DP(); // 状压DP
        ans=dp[tot][k+1];
        for (i=1;i<=k;i++)
            ans+=a[x[i]][y[i]];
        printf("%d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-30 15:53:00

HDU 4568 旅行商问题的相关文章

hdu 4568 spfa 最短路算法+旅行商问题

http://acm.hdu.edu.cn/showproblem.php?pid=4568 Problem Description One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could. The area can be represented a

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

hdu 4568 Hunter 最短路+dp

Hunter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2014    Accepted Submission(s): 615 Problem Description One day, a hunter named James went to a mysterious area to find the treasures. Jame

HDU 4568 Hunter 最短路+状压DP

题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝藏的最小花费,如果一次不能拿走所有能拿到的或者根本拿不到任何宝藏,输出0. 解法:看到k的范围应该想到状态压缩,将每个格子都看成一个点,再新建两个点,一个表示边界外的起点,用0表示,一个表示边界外的终点,用n*m+1表示,然后相互建边,建有向边,边权为终点格子的花费值,(其实都不用建边,直接跑最短路也行)

hdu 4568 bfs + 状压dp

//这题的数据是不是有问题... 不考虑宝藏一个也拿不到也能AC... 1 #include "bits/stdc++.h" 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 int T; 5 int N, M; 6 int mat[210][210]; 7 int K; 8 int tot_tra, tra[210][210]; 9 10 //dp parameters 11 int dis_tra_broder[20],

ACM总结——dp专辑(转)

感谢博主——      http://blog.csdn.net/cc_again?viewmode=list       ----------  Accagain  2014年5月15日 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. 本人动态规划博客地址:http://blog.csdn.net/cc_again/article/category/1261899 ***********************

2013 长沙邀请赛 ADEGH 题解

HDU 4565 So Easy! 类似fib的构造 设Fn = x + y*sqrt(b) 啪啦啪啦 #include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <iostream> using namespace std; typedef vector<long long> vec; typedef vector<vec&g

【DP专辑】ACM动态规划总结

转载请注明出处,谢谢.   http://blog.csdn.net/cc_again?viewmode=list          ----------  Accagain  2014年5月15日 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. 本人动态规划博客地址:http://blog.csdn.net/cc_again/article/category/1261899 ******************

(转)dp动态规划分类详解

dp动态规划分类详解 转自:http://blog.csdn.NET/cc_again/article/details/25866971 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. ****************************************************************************************** 动态规划(英语:Dynamic programm