HDU - 4568 Hunter 2013长沙邀请赛

题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4568


题意:给你一个四联通的长方形,每一个格子中都有一个值,你走到这个格子要耗费这些体力,-1代表无法通过,其中有一些格子里面有宝藏,一个人可以从边界的任意一个点进入,边界的任意一个点出去,问如果他得到了所有的宝藏,耗费的体力最少是多少。


分析:总共有40000个格子,对这40000个格子分析显然不可能,于是先用Dijstra将有宝藏的格子之间的最短路算出来,然后这些格子都要访问到,现在要确定访问顺序,当格子数在10以下的时候,可以使用暴力搜索,时间复杂度是n!,但是题目中给了宝藏数最多为13,于是不能爆搜,就要用到状压DP,dp[i][j],i为用二进制保存每个宝藏是否被取得,j为最后一个走到的是哪一个宝藏,然后就可以得到dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+g[k][j]);j是当前走的格子,k为上一个,在走第一个宝藏的时候要加上边界到这个格子的距离,最后一个同理。


代码:

#include <bits/stdc++.h>

using namespace std;

const int MAXN=40100;

struct qnode
{
    int v;
    int c;
    qnode(int _v=0,int _c=0):v(_v),c(_c) {}
    bool operator <(const qnode &r)const
    {
        return c>r.c;
    }
};

struct Edge
{
    int v,cost;
    Edge(int _v=0,int _cost=0):v(_v),cost(_cost) {}
};

int m,n;
int T,x,y,xx1,yy1,a[205][205],ge,wei[15],g[15][15],dp[1<<13][15],ans;
int r[4]={0,0,1,-1},c[4]={1,-1,0,0};
vector<Edge> E[MAXN];
bool vis[MAXN];
int dist[MAXN];

void Dijkstra(int len,int start)
{
    memset(vis,0,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    priority_queue<qnode>que;
    while(!que.empty())
        que.pop();
    dist[start]=0;
    que.push(qnode(start,0));
    qnode tmp;
    while(!que.empty())
    {
        tmp=que.top();
        que.pop();
        int u=tmp.v;
        if(vis[u])
            continue;
        vis[u]=true;
        for(int i=0; i<E[u].size(); i++)
        {
            int v=E[tmp.v][i].v;
            int cost=E[u][i].cost;
            if(!vis[v]&&dist[v]>dist[u]+cost)
            {
                dist[v]=dist[u]+cost;
                que.push(qnode(v,dist[v]));
            }
        }
    }
}

void addedge(int u,int v,int w)
{
    E[u].push_back(Edge(v,w));
}

void init()
{
    for(int i=0;i<=n;i++)
        E[i].clear();
}

int js(int h1,int h2)
{
    return h1*y+h2;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--)
    {
        cin>>x>>y;
        n=x*y;
        init();
        for(int i=0;i<x;i++)
            for(int j=0;j<y;j++)
                cin>>a[i][j];
        for(int i=0;i<x;i++)
        {
            for(int j=0;j<y;j++)
            {
                for(int k=0;k<4;k++)
                {
                    xx1=i+r[k];
                    yy1=j+c[k];
                    if(xx1>=0&&xx1<x&&yy1>=0&&yy1<y&&a[xx1][yy1]!=-1)
                        addedge(js(i,j),js(xx1,yy1),a[xx1][yy1]);
                }
            }
        }
        cin>>ge;
        for(int i=0;i<ge;i++)
        {
            cin>>xx1>>yy1;
            wei[i]=js(xx1,yy1);
        }
        for(int i=0;i<ge;i++)
        {
            Dijkstra(n,wei[i]);
            for(int j=0;j<ge;j++)
                g[i][j]=dist[wei[j]];
        }
        for(int i=0;i<x;i++)
            for(int j=0;j<y;j++)
                if((i==0||j==0||i==x-1||j==y-1)&&a[i][j]!=-1)
                    addedge(n,js(i,j),a[i][j]);
        for(int i=0;i<ge;i++)
        {
            Dijkstra(n+1,n);
            g[ge][i]=dist[wei[i]];
            g[i][ge]=dist[wei[i]]-a[wei[i]/y][wei[i]%y];
        }
        memset(dp,0x3f,sizeof(dp));
        for(int i=0;i<ge;i++)
            dp[1<<i][i]=g[ge][i];
        int s=1<<ge;
        for(int i=1;i<s;i++)
            for(int j=0;j<ge;j++)
                if((i>>j)&1)
                    for(int k=0;k<ge;k++)
                        if(k!=j&&(i>>k)&1)
                            dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+g[k][j]);
        ans=1e8;
        for(int i=0;i<ge;i++)
            ans=min(ans,dp[s-1][i]+g[i][ge]);
        if(ans==1e8)
            cout<<0<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值