//
// 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网上的,手懒了 = =。。。