您的位置:首页 > 其它

NYOJ 7 街区最短路径问题

2013-12-04 00:59 483 查看
看到这道题时自己推了会 并没有找到什么规律   在题解中出题人提示:  横纵坐标的中位数!    好吧 这道题第一个问题邮局位置就确定了,即将输入的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;
}
好吧,我自己感觉自己解释的就不清晰   大家人为应该怎么写题解更好 可以给我下建议  下回我会注意!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息