浅谈由hunter想到的状压dp

//
//  main.cpp
//  hunter hdu4568
//
//  Created by 刘鑫伟 on 14-8-4.
//  Copyright (c) 2014年 刘鑫伟. All rights reserved.
//

/*  Tunnels + hunters  看了两道这个类型的状压  终于想通了有关这样有地图的题该如何处理
     首先  类似这样的题都会先给你一个地图  然后让你用一个方式遍历图中的某些点 求类似于最小距离的问题
     这样的题也就类似于tsp吧    首先  我们得知道状压dp也不能直接对图下手   图必然需要转化  所以这个时候
    我们想到应该把图进行处理  来得到每两个点之间的距离  有的题还需要得到每个点和边界的距离 求法类似。  我的处理方式是有多少个点就做多少次bfs   每次都遍历全图  如果发现某一步到达了边界点或其他目标点  就把广搜的步数赋值成对应点的距离  建议用  d[i][j]存距离   i=3,j=5表示3到5的距离  i=3,j=0表示到边界的距离   然后全部做完以后   这时候本身的图就没用了  我们得到了一系列距离。  然后就可以开始dp求值了    
 
     关于dp求值     结合网上看的一些方式,这里说两种   一种是我想的 需要dp多次的  一种是dp一次  但是需要多加一维   感觉效果其实类似  可能更省空间一些  一种是dp[i][j] 表示j开始 到达i状态   一种是需要做k次  每次都是dp[i] 然后记录最小值     这里初始化的时候一般是哪个点开始  就把哪个点对应状态 dp[1<<i]设置成0  其他都是-1   然后转移过程中如果遇到前置状态是 -1  直接continue  
 
      最后就是关于dp方程的写法  
     1:   for(i=1;i<(1<<m);i++)
            for(j=1;j<=m;j++)
           {
                  int temp=1<<(j-1);
                  if(temp&i)
                 {
                     dp[i]=dp[i-temp]+v[temp]
                 }
           }
      2:   for(i=1;i<(1<<m);i++)
               for(j=1;j<=m;j++)
               {
                   int temp=1<<(j-1);
                   if(!temp&i)
                   {
                       dp[i|temp]=dp[i]+v[temp]
                   }
                }

 */

#include <sstream>
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
#define maxn 210
#define inf 2139062143
using namespace std;

int map[maxn][maxn];
int tre[maxn][maxn];
int N,M;
int K;
int g[30][30];
int cost[30];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int add[20];
int dp[1<<14][15];

struct Heapnode
{
    int d,u;
    Heapnode(){}
    Heapnode(int x,int y)
    {
        u=x,d=y;
    }
    bool operator<(const Heapnode& r) const
    {
        return d>r.d;
    }
};
int d[210*210];
bool done[210*210];

void DJK(int s,int id)
{
    int i,j;
    priority_queue<Heapnode> q;
    for(i=0;i<N*M;i++)
    {
        d[i]=inf;
    }
    d[s]=0;
    memset(done,false,sizeof(done));
    q.push(Heapnode(s,0));
    while(!q.empty())
    {
        Heapnode pre=q.top();
        q.pop();
        int u=pre.u;
        if(done[u]) continue;
        done[u]=true;
        int x,y,nx,ny;
        x=u/M,y=u%M;
        
        if(tre[x][y]!=-1)
        {
            g[id][tre[x][y]]=d[u];
        }
        if(x==0||x==N-1||y==0||y==M-1)
        {
            cost[id]=min(cost[id],d[u]);
        }
        
        for(i=0;i<4;i++)
        {
            nx=x+dir[i][0],ny=y+dir[i][1];
            if(map[nx][ny]==-1) continue;
            if(nx<0||nx>=N||ny<0||ny>=M) continue;
            
            int nu=nx*M+ny;
            if(d[nu]>d[u]+map[nx][ny])
            {
                d[nu]=d[u]+map[nx][ny];
                q.push(Heapnode(nu,d[nu]));
            }
        }
    }
}

int main()
{

    int i,j,k;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&N,&M);
        for(i=0;i<N;i++)
        {
            for(j=0;j<M;j++)
            {
                scanf("%d",&map[i][j]);
            }
        }
        memset(tre,-1,sizeof(tre));
        scanf("%d",&K);
        for(i=0;i<K;i++)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            tre[a][b]=i;
            add[i]=a*M+b;
        }
        memset(g,0x7f,sizeof(g));
        for(i=0;i<K;i++)
        {
            g[i][i]=0;
            cost[i]=inf;
            DJK(add[i],i);
        }
        
        memset(dp,0x7f,sizeof(dp));
        for(i=0;i<K;i++)
        {
            int x,y;
            x=add[i]/M,y=add[i]%M;
            dp[1<<i][i]=cost[i]+map[x][y];
        }
        
        for(i=0;i<(1<<K);i++)
        {
            for(j=0;j<K;j++)
            {
                if((i&(1<<j))==0) continue;
                if(dp[i][j]==inf) continue;
                
                for(k=0;k<K;k++)
                {
                    if(i&(1<<k)) continue;
                    
                    dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+g[j][k]);
                }
            }
        }
        
        int ans=inf;
        for(i=0;i<K;i++)
        {
            ans=min(ans,dp[(1<<K)-1][i]+cost[i]);
        }
        
        printf("%d\n",ans);
    }
    return 0;
}




代码是cv网上的,手懒了 = =。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值