【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,待我好好补一补搜索再来更新吧~
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; }
相关文章推荐
- 编程:对经验世界的析构与建构
- android中RelativeLayout无法填充ScrollView布局的问题
- Office 365 系列三 ------ 创建Office 365普通账号
- 图像颜色处理(ColorMatrix)
- 【转】学习使用Jmeter做压力测试(二)--压力测试的实施
- Java基础01 从HelloWorld到面向对象
- win8.1系统开机后黑屏且主板伴有警报声的原因及解决方法
- jQuery实现简单的文件上传进度条效果
- MySQL 忘记root密码解决办法
- asp.net 时间格式大全
- HTTP Method 之 Post VS. Get
- LeetCode Path Sum
- CCBPM H5版本中组织结构集成以及与外部数据源同步介绍
- 你在哪编程?你的程序原料是什么?
- Java快速教程
- 【转】学习使用Jmeter做压力测试(一)--压力测试基本概念
- jQuery Ajax 实例详解 ($.ajax、$.post、$.get)
- 在线代码转换工具
- 【转】jmeter压力测试
- ubuntu下打开windows里的txt文件乱码解决