关闭

NYOJ 7 街区最短路径问题

标签: c快速排序遍历搜索bfs
541人阅读 评论(0) 收藏 举报
分类:
看到这道题时自己推了会 并没有找到什么规律   在题解中出题人提示:  横纵坐标的中位数!    好吧 这道题第一个问题邮局位置就确定了,即将输入的x轴和y轴的数字排序取两者的中位数  两者的中位数就是邮局的位置 即到所有用户最短距离的位置   要问我为什么怎样  其实我自己也没搞太明白怎么找出的规律   不过在这先用着这个结论。解决了邮局位置的问题  接下来我们该解决怎么求出该位置到所有用户的距离是多少!这样就要用广搜了  广搜时需要用队列  我们需要队列存储遍历过得x(横坐标)和y(纵坐标);广搜时是从邮局位置开始搜索的的, 分别是四个方向搜索,如果该方向位置没有搜索过  就入队列!同时在搜索时记得矩阵有一个改变 就是该矩阵位置的值加一赋给他四周没被遍历过得位置(没有图也许这样说得不是太明白, 不过我在代码中注释好多,看过代码应该就知道说得什么意思了)等找到所有位置后  它本身矩阵位置的值就是邮局到该点的距离。把所有用户所处矩阵位置的值相加  就得到邮局到所有用户的最小距离之和!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int a[30], b[30],c[110][110], c1[110][110], e[30], f[30];
//a数组存的是横坐标 b数组存的是纵坐标 因为要对a和b数组排序  所以有添加两个数组e和f保存未排序时的a与b数组
//c数组是一个矩阵  c1数组是来记录该位置是否被访问过 
struct m{
	int l, k;
	int w;
}d[1500];//广搜时用到的队列  稍微开大点  我开始时开的有点小了 
int cmp(const void *a, const void *b)//快速排序用到的一个函数 
{
	return *(int *)a - *(int *)b;
}
void bfs(int x, int y, int m)//广搜函数 
{
	int front = 0, rear = 0, i, j, count = 0;
	d[rear].l = x; d[rear].k = y; d[rear].w = 1; rear++;
	if(c[x][y] == -10)
	{
		c[x][y] = 0;
		c1[x][y] = 1;
		count++;
	}//先判断由中位数得到的位置是不是已经有用户住,有的话计数器count加一 
	while(count != m)//当搜到所有的用户全部搜到时结束搜索 
	{
		if(d[front].l - 1 >= 0 && c1[d[front].l - 1][d[front].k] != 1)
		{
			if(c[d[front].l - 1][d[front].k] == -10) 
				count++;//如果该点是用户计数器加一 
			d[rear].l = d[front].l - 1; d[rear].k = d[front].k; d[rear].w = 1; rear ++;
			c[d[front].l - 1][d[front].k] = c[d[front].l][d[front].k] + 1;//本身加一的值赋给它四周未被遍历过的位置
			c1[d[front].l - 1][d[front].k] = 1;//当访问过就赋值为一	
		}
		if(d[front].l + 1 < 105 && c1[d[front].l + 1][d[front].k] != 1)
		{
			if(c[d[front].l + 1][d[front].k] == -10)
				count++;
			d[rear].l = d[front].l + 1; d[rear].k = d[front].k; d[rear].w = 1; rear++;
			c[d[front].l + 1][d[front].k] = c[d[front].l][d[front].k] + 1;//本身加一的值赋给它四周未被遍历过的位置
			c1[d[front].l + 1][d[front].k] = 1;
		}
		if(d[front].k - 1 >= 0 && c1[d[front].l][d[front].k - 1] != 1)
		{
			if(c[d[front].l][d[front].k - 1] == -10)
				count++;
			d[rear].l = d[front].l; d[rear].k = d[front].k - 1; d[rear].w = 1; rear++;
			c[d[front].l][d[front].k - 1] = c[d[front].l][d[front].k] + 1;//本身加一的值赋给它四周未被遍历过的位置
			c1[d[front].l][d[front].k - 1] = 1;	
		}
		if(d[front].k + 1 < 105 && c1[d[front].l][d[front].k + 1] != 1)
		{
			if(c[d[front].l][d[front].k + 1] == -10)
				count++;
			d[rear].l = d[front].l; d[rear].k = d[front].k + 1; d[rear].w = 1; rear++;//本身加一的值赋给它四周未被遍历过的位置
			c[d[front].l][d[front].k + 1] = c[d[front].l][d[front].k] + 1;
			c1[d[front].l][d[front].k + 1] = 1;	
		}
		front++;
	}
	
}
int f1(int m, int *e)//这个函数就是把用户所处矩阵各个位置相加
{
	int sum = 0, i;
	for(i = 0; i < m; i++)
	{
		sum += c[e[i]][f[i]];
	}
	return sum;
}
int main()
{
	int t, m, i, x, y, temp1, temp2, sum;
	//int e[30], e1[30];
	scanf("%d", &t);
	while(t--)
	{
		for( i = 0; i < 105; i++ )
			d[i].w = 0;
		memset(c, 0, sizeof(c));
		memset(c1, 0, sizeof(c1));//把矩阵初始为零值
		scanf("%d", &m);
		for(i = 0; i < m; i++)
		{
			scanf("%d%d", &x, &y);
			a[i] = e[i] = x;
			b[i] = f[i] = y;
			c[x][y] = -10;//有用户的位置被赋值为-10
		}
		qsort(a, m, sizeof(int), cmp);//快速排序 
		qsort(b, m, sizeof(int), cmp);
		if(m % 2)
		{
			temp1 = a[m / 2];
			temp2 = b[m / 2];
			bfs(temp1, temp2, m);
			sum = f1(m, e);
			printf("%d\n", sum);
		}
		else
		{
			temp1 = (a[m / 2] + a[m / 2 - 1]) / 2;
			temp2 = (b[m / 2] + b[m / 2 - 1]) / 2;
			bfs(temp1, temp2, m);
			sum = f1(m, e);
			printf("%d\n", sum);
		}
	}
	return 0;
}
好吧,我自己感觉自己解释的就不清晰   大家人为应该怎么写题解更好 可以给我下建议  下回我会注意!
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:6349次
    • 积分:170
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:1篇
    • 评论:1条
    文章分类
    文章存档
    最新评论