poj-3026

31 篇文章 0 订阅
//664K	79MS	G++
#include <cstdio>
#include <cstring>
#include <queue>


using namespace std;


#define LENGTH_MAX 54
#define NODE_MAX 110
#define WALL -1


int maze[LENGTH_MAX][LENGTH_MAX]; // 0: nothing -1: wall >0: S or A's id


int node_distance[NODE_MAX][NODE_MAX];


struct Node {
	int x;
	int y;
};


typedef struct Node Node;
Node nodes[NODE_MAX];
int nodeNum;
int mazeLength;
int mazeWidth;


struct BFSNode {
	int x;
	int y;
	int distance;
};


typedef struct BFSNode BFSNode;


queue<BFSNode> BFSQueue;


int BFSFlag[NODE_MAX][NODE_MAX];


void processNode(int curX, int curY, int curDistance, int beginId) {
	BFSFlag[curX][curY] = 1;
	int upNodeId = maze[curX][curY];
	if (upNodeId > 0) { // Node in this (x,y)
		node_distance[beginId][upNodeId] = curDistance + 1; // get its shortest distance
	} else if (upNodeId == WALL) {
		return;
	}
	BFSNode upNode;
	upNode.x = curX;
	upNode.y = curY;
	upNode.distance = curDistance + 1;
	BFSQueue.push(upNode);
}


void BFS(int beginId) {
	while(BFSQueue.size()) {
		BFSQueue.pop();
	}


	memset(BFSFlag, 0, sizeof(BFSFlag));


	int beginX = nodes[beginId].x;
	int beginY = nodes[beginId].y;


	BFSNode beginNode;
	beginNode.x = beginX;
	beginNode.y = beginY;
	beginNode.distance = 0;
	BFSFlag[beginX][beginY] = 1;


	BFSQueue.push(beginNode);
	while(BFSQueue.size()) {
		BFSNode curNode = BFSQueue.front();
		BFSQueue.pop();
		int curX = curNode.x;
		int curY = curNode.y;
		int distance = curNode.distance;
		
		//up
		if ((curY-1>=0) && !BFSFlag[curX][curY-1]) { //if can up
			processNode(curX, curY-1, distance, beginId);
		}


		//Down
		if ((curY + 1 <= mazeWidth-1) && !BFSFlag[curX][curY+1]) {
			processNode(curX, curY+1, distance, beginId);
		}


		//left
		if ((curX-1 >= 0) && !BFSFlag[curX-1][curY]) {
			processNode(curX-1, curY, distance, beginId);
		}


		//right
		if ((curX + 1 <= mazeLength-1) && !BFSFlag[curX+1][curY]) {
			processNode(curX+1, curY, distance, beginId);
		}
		BFSFlag[curX][curY] = 2;
	}


}


void getNodeDistance() {
	for (int i = 1; i <= nodeNum; i++) {
		BFS(i);
	}


	// for (int i = 1; i <= nodeNum; i++) {
	// 	for (int j = 1; j <= nodeNum; j++) {
	// 		printf("%d -> %d: %d\n", i,j, node_distance[i][j]);
	// 	}
	// }


}


int key[NODE_MAX];
char visited[NODE_MAX];


#define INF 99999999


void Prim() {
	int distanceSum = 0;
	for (int i = 1 ; i <= nodeNum; i++) {
		key[i] = INF;
		visited[i] = 0;
	}
	key[1] = 0;


	for (int i = 1; i <= nodeNum; i++) {
		int minId = -1;
		int minDistance = INF;
		for (int j = 1; j <= nodeNum; j++) {
			if (!visited[j] && minDistance > key[j]) { // get the shortest unprocessed node. 
				minId = j;
				minDistance = key[j];
			}
		}
		visited[minId] = 1;
		// printf("%d %d\n", minId, minDistance);
		distanceSum += minDistance;


		for (int j = 1; j <= nodeNum; j++) {
			if (!visited[j] && node_distance[minId][j] > 0) { // check minId's adjancey
				if (key[j] > node_distance[minId][j]) {
					key[j] = node_distance[minId][j];
				}
			}
		}
	}
	printf("%d\n", distanceSum);
}


void solve() {
	getNodeDistance();
	Prim();
}


int main() {
	int caseNum;
	char tmp[LENGTH_MAX] = "";
	// scanf("%d", &caseNum);
	gets(tmp);
	sscanf(tmp , "%d", &caseNum);
	for (int i = 0; i < caseNum; i++) {
		nodeNum = 0;
		memset(maze, 0, sizeof(maze));
		memset(node_distance, 0, sizeof(node_distance));
		memset(nodes, 0, sizeof(nodes));
		// scanf("%d %d", &mazeLength, &mazeWidth);
		
		char mazeline[LENGTH_MAX] = "";
		gets(mazeline);
		// printf("! %s", mazeline);
		sscanf(mazeline , "%d %d", &mazeLength, &mazeWidth);
		// printf("%d %d\n", mazeLength, mazeWidth);
		for (int i = 0; i < mazeWidth; i++) {
			memset(mazeline, 0, sizeof(mazeline));
			gets(mazeline);
			// printf("%s\n", mazeline);
			for (int j = 0; j < mazeLength; j++) {
				if (mazeline[j] == '#') {
					maze[i][j] = WALL;
				} else if (mazeline[j] == 'S' || mazeline[j] == 'A') {
					// printf("nodeNum %d %c\n", nodeNum, mazeline[j]);
					nodeNum++;
					maze[i][j] = nodeNum;
					nodes[nodeNum].x = i;
					nodes[nodeNum].y = j;
				}
			}
		}
		// printf("nodeNum %d\n", nodeNum);
		solve();
	}
}


算是一道好的综合题,转化和综合难度都适中.

初看题可能不是很好理解题意,不过有个关键的地方就是在最开始搜索迷宫 或者 遇到alien的时候,队伍可以分裂为数个进行搜索,

这其实就暗地说明了从任何一个 'A'/'S' 可以到达任何其他的'A'/'S'(从S搜索开始, 可以分裂为数个队伍到其他的任何数量的'A', 而在‘A’这里,队伍同样可以分裂数个到其他任何

的'A'/'S', 题目还专门说明了搜索队伍大于100,保证了就算再分裂所有的alien(最多100)也可以被到达)

这样就可以把 'A'/'S'看做图的V, 并且每个V都是互相直接可达的(题目说明了),

而结合题目要求的所有队列最后经过的路径的总长度的最小值,其实就是能遍历每个V的最短路径了,即最小生成树。

到了这里,就到第一个考点了,题目没有直接给出每个'A'/'S'之间的距离,而是给了一个字符表示的迷宫分布图。

每个V之间的(最短)距离都要用这张图求出来,这个问题就转化成了迷宫求最短路径了(每两个V之间的最短距离)。

而求迷宫最短路径都是用BFS,这里如果按照朴素思维,就要一一求两个点之间的最短距离,需要100*99次, 这样铁定TLE.

不过因为用的是BFS,因此可以把求两个点的最短路径问题变为,从某个源点开始遍历迷宫所有位置,求出与其他点最短路径的问题(因为遍历过程中必然会经过其他所有的点,并且一定是最短路径),这样对于每个点只需要BFS一次就可以了,最多只需要100次,满足了时间需求。(其实上面的次数计算不严格,因为在本题中,边是无向的,求出了A->B的最短距离 ,B->A的最短距离也就得到了,不过即使这样,还是后者效率高)。

得到了边的权值以后,直接Prim算法求出最小生成树的长度即可.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值