您的位置:首页 > 其它

【UVA 10307 Killing Aliens in Borg Maze】最小生成树, kruscal, bfs

2015-11-20 14:40 465 查看
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20846


POJ 3026是同样的题,但是内存要求比较严格,并是没有过。。。

对以迷宫形式给定的一些点求最小生成树,不过这里的边并不是抽象的两点间笛卡尔距离,也不是折线距离(迷宫中有障碍),而是需要用四个方向的搜索来求。

用bfs求出任两点间的最短距离后,可用kruscal求出最小生成树。

这次值得一提的是对并查集的一点改造:由于每个顶点由一组(x,y)坐标唯一确定,而并查集的元素应是能用一个整数唯一确定的,所以要将(x,y)坐标的集合映射到整数集合。联想到了最近课内学的信道的“分频复用”,和实时操作系统uCOS-II的任务就绪表的数据结构和算法。于是就有了如下做法,其实很常见了~

x,y坐标范围是[0,50],50<2^6,因此可用一个int型(2^31)的低7位存y坐标,8~14位存x坐标,14<31,一个整型完全可以存下。这样一个点可由一个int型数(低14位)完全确定,并且以每维2^14为size开二维数组vis和dis也可以开下。

经检验这个做法可行,其实就是模仿底层,把基本型当作结构体看待,每位的语义是约定好的,自己编码自己解码~

代码在UVA过了(没限制内存),在POJ上还是MLE,待我好好补一补搜索再来更新吧~

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
using namespace std;
const int MAX_S=55;
const int MAX_N=105;
struct Point
{
int x,y;
Point(){}
Point(int xx,int yy):x(xx),y(yy){}
};

struct Edge
{
Point u,v;
int w;
}e[MAX_N*MAX_N];
bool cmp(const Edge e1,const Edge e2)
{
return e1.w<e2.w;
}

int par[(MAX_S<<7)+MAX_S];
void init()
{
memset(par,-1,sizeof(par));
}
int find(int x)
{
if(par[x]==-1) return x;
return par[x]=find(par[x]);
}
void unite(Point p1,Point p2)
{
int x=(p1.x<<7)+p1.y;
int y=(p2.x<<7)+p2.y;
x=find(x);
y=find(y);
if(x==y) return ;
par[x]=y;
}

bool same(Point p1,Point p2)
{
int x=(p1.x<<7)+p1.y;
int y=(p2.x<<7)+p2.y;
return find(x)==find(y);
}

int T;
int w,h;
int n,m;
char maze[MAX_S][MAX_S];
int dx[]={0,0,1,-1},dy[]={1,-1,0,0};

typedef pair<Point,int> P;
int vis[MAX_S][MAX_S];
int dis[(MAX_S<<7)+MAX_S][(MAX_S<<7)+MAX_S];

void bfs(int x,int y)
{
int poi=(x<<7)+y;
memset(vis,0,sizeof(vis));
queue<P> que;//Point,step
que.push(P(Point(x,y),0));
vis[x][y]=1;
while(!que.empty())
{
Point p=que.front().first;
int step=que.front().second;
que.pop();
for(int i=0;i<4;i++)
{
int nx=p.x+dx[i];
int ny=p.y+dy[i];
int npoi=(nx<<7)+ny;
if(nx<0||ny<0||w<=nx||w<=ny||vis[nx][ny]) continue;
if(maze[nx][ny]=='#'){vis[nx][ny]=1; continue;}
if(dis[poi][npoi]||poi==npoi) continue;
que.push(P(Point(nx,ny),step+1));
vis[nx][ny]=1;
if((maze[nx][ny]=='A'||maze[nx][ny]=='S')&&poi!=npoi)
{
e[m].u=Point(x,y);
e[m].v=Point(nx,ny);
dis[npoi][poi]=dis[poi][npoi]=e[m].w=step+1;
m++;
}
}
}
}

int kruscal()
{
init();
int ans=0;
for(int i=0;i<m;i++)
{
if(!same(e[i].u,e[i].v))
{
unite(e[i].u,e[i].v);
ans+=e[i].w;
}
}
return ans;
}

int main()
{
freopen("3026.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&w,&h);
n=0;
getchar();
for(int i=0;i<h;i++)
{
fgets(maze[i],w,stdin);
gets(maze[i+1]);
}
m=0;
memset(dis,0,sizeof(dis));
for(int i=0;i<h;i++)
{
for(int j=0;j<w;j++)
if(maze[i][j]=='A'||maze[i][j]=='S') bfs(i,j);
}
/*
for(int i=0;i<m;i++)
printf("%d %d -> %d %d = %d\n",e[i].u.x,e[i].u.y,e[i].v.x,e[i].v.y,e[i].w);
*/
sort(e,e+m,cmp);
printf("%d\n",kruscal());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: