POJ 2688 Cleaning Robot(状压dp+bfs)

题目链接:http://poj.org/problem?id=2688

大意:给出一个矩形图,回答从起点出发要经过所有指定点的最短路径长度。如果不能经过所有点就输出-1。

因为指定点的数量不超过10,图的大小不超过20×20,所以可以先bfs预处理构建起点和指定点的邻接矩阵。

然后状压dp就好了。dp[i][j]表示状态i,路径最后一个点为j的最短路径长度。i的每位代表哪些点走了。

(ps:是否能经过所有点特判一下就可以了)

/*--------------------------------------------------------
                       Author:log                         
   Created Time:2016年04月13日 星期三 20时02分50秒
--------------------------------------------------------*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <map>

using namespace std;

const int maxn=25;
const int inf=0x3f3f3f3f;

struct Node{
	int x,y;
	int d;
	Node(){}
	Node(int x,int y,int d):x(x),y(y),d(d){}
}node[maxn];
int grap[maxn][maxn];
bool vis[maxn][maxn];
int edge[maxn][maxn];
int dp[1<<11][11];
Node q[maxn*maxn];
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
int w,h;

void bfs(int id,int num){
	memset(vis,0,sizeof(vis));
	int l=0,r=0;
	q[r++]=node[id];
	vis[node[id].x][node[id].y]=true;
	Node u;
	int xt,yt;
	int cot=0;
	while(l<r){
		u=q[l++];
		for(int i=0;i<4;i++){
			xt=u.x+dx[i];
			yt=u.y+dy[i];
			if(xt<0||xt>=h||yt<0||yt>=w)continue;
			if(vis[xt][yt]||grap[xt][yt]==-2)continue;
			if(grap[xt][yt]>0){
				edge[id][grap[xt][yt]]=edge[grap[xt][yt]][id]=u.d+1;
				cot++;
			}
			if(cot>=num)return ;
			vis[xt][yt]=true;
			q[r++]=Node(xt,yt,u.d+1);
		}
	}
}

int solve(int n){
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)if(i!=j)
			if(edge[i][j]==0)return -1;
	int state=1<<n;
	for(int i=0;i<state;i++){
		for(int j=0;j<n;j++)dp[i][j]=inf;
	}
	dp[1][0]=0;
	for(int i=1;i<state;i++){
		for(int j=0;j<n;j++){
			if(i&(1<<j)==0)continue;
			for(int k=0;k<n;k++){
				if(i&(1<<k))continue;
				dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+edge[j][k]);
			}
		}
	}
	int ans=inf;
	for(int i=0;i<n;i++){
		ans=min(dp[state-1][i],ans);
	}
	if(ans==inf)return -1;
	return ans;
}

int main(){
	char c;
	int cot;
	while(scanf("%d %d",&w,&h)==2&&(w||h)){
		cot=0;
		for(int i=0;i<h;i++){
			getchar();
			for(int j=0;j<w;j++){
				c=getchar();
				switch(c){
					case '.':grap[i][j]=-1;break;
					case 'o':grap[i][j]=0;node[0]=Node(i,j,0);break;
					case '*':grap[i][j]=++cot;node[cot]=Node(i,j,0);break;
					default:grap[i][j]=-2;break;
				}
			}
		}
		memset(edge,0,sizeof(edge));
		for(int i=0;i<cot;i++){
			grap[node[i].x][node[i].y]=0;
			bfs(i,cot-i);
		}
		printf("%d\n",solve(cot+1));
	}
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值