POJ_3026_Borg Maze_最小生成树

打ACM就像是表白,像我这样的人也就指着AC题目感受一下表白成功的感觉了。


题意:

方格迷宫内有一些外星人,要吧他们练成一棵最小生成树,求树长度。只有外星人和源点(和外星人的点没区别)可以当树的节点(这个我死活没看出来在哪里体现了,还好看到讨论区里的人说)


Input

On the first line of input there is one integer, N <= 50, giving the number of test cases in the input. Each test case starts with a line containg two integers x, y such that 1 <= x,y <= 50. After this, y lines follow, each which x characters. For each character, a space `` '' stands for an open space, a hash mark ``#'' stands for an obstructing wall, the capital letter ``A'' stand for an alien, and the capital letter ``S'' stands for the start of the search. The perimeter of the maze is always closed, i.e., there is no way to get out from the coordinate of the ``S''. At most 100 aliens are present in the maze, and everyone is reachable.

Output

For every test case, output one line containing the minimal cost of a succesful search of the maze leaving no aliens alive.
所以这个题肯定要先建图,先对每个点bfs求他们到其他点的距离,然后跑个prim就行了(prim复杂度为v^2,kruskal为eloge,这个图是密集图,跑prim更划算)

写的时候一开始被bfs坑爆了哦凑。。。


代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define mxn 60
#define inf 0x3f3f3f3f
#define mxp 1050
char map[mxn][mxn];
int dist[mxn][mxn];
int n,m;
int cnt;
int rec[mxn][mxn];
struct point{
	int x,y;
	point(int _x,int _y){x=_x,y=_y;}
	point(){}
}p[mxp];
void bfs(int id){
	point q[mxn*mxn];
	int head=0,tail=1;
	int d[mxn][mxn], mx[4]={0,1,0,-1},my[4]={1,0,-1,0};
	bool flag[mxn][mxn];
	memset(d,0x3f,sizeof(d));
	memset(flag,0,sizeof(flag));
	q[head]=p[id];
	flag[p[id].x][p[id].y]=true;
	d[p[id].x][p[id].y]=0;
	while(head!=tail){
		point now=q[head];
		if(rec[now.x][now.y]!=-1)
			dist[id][rec[now.x][now.y]]=d[now.x][now.y];
		for(int i=0;i<4;++i){
			int nx=now.x+mx[i],ny=now.y+my[i];
			if(nx<0||ny<0||nx>=n||ny>=m||flag[nx][ny])
				continue;
			if(map[nx][ny]=='#')	continue;
			q[tail++]=point(nx,ny);
			d[nx][ny]=d[now.x][now.y]+1;
			flag[nx][ny]=true;
		}
		++head;
	}
}
int prim(){
	int dis[mxp];
	memset(dis,0x3f,sizeof(dis));
	int now=0,ret=0;
	dis[now]=-1;
	for(int i=1;i<cnt;++i){
		int min_e=inf,min_p;
		for(int j=0;j<cnt;++j){
			if(dis[j]==-1)	continue;
			dis[j]=min(dis[j],dist[now][j]);
			if(min_e>dis[j]){
				min_e=dis[j];
				min_p=j;
			}
		}
		ret+=min_e;
		now=min_p;
		dis[min_p]=-1;
	}
	return ret;
}
int main(){
	int cs;
	scanf("%d",&cs);
	while(cs--){
		cnt=0;
		memset(rec,-1,sizeof(rec));
		memset(map,0,sizeof(map));
		scanf("%d%d",&m,&n);
		char eat[mxp];
		gets(eat);
		for(int i=0;i<n;++i)
			gets(map[i]);
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j)
				if(map[i][j]=='A'||map[i][j]=='S'){
					rec[i][j]=cnt;
					p[cnt].x=i,p[cnt++].y=j;
				}
		for(int i=0;i<cnt;++i)
			bfs(i);
		int ans=prim();
		printf("%d\n",ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值