题目链接:
题目83:允许向上下左右移动的情况下从左上角到右下角的最小路径和是多少?
通过人数:8961
题目分析:
前面的两道题都用动态规划做了,而这一问缺是典型的单源最短路径问题,我使用了Dijkstra算法。
解题过程(代码仅供参考,因为偷懒,代码风格什么的实在不好意思...):
【原谅我因为偷懒,使用纯c风格写了这个图论算法...】
一、首先,从文件中读入数据
FILE *fp = fopen("matrix.txt", "r");
char c[110000];
for (int i = 0; i < 80; i++)
{
fgets(c, 100000, fp);
char * pc = c;
int l = 1;
sscanf(pc, "%d", &a[i][0]);
while(1)
{
if (*pc == 0)
break;
if (*pc == ',')
{
sscanf(pc+1, "%d", &a[i][l]);
l++;
}
pc++;
}
}
这步和81、82题是一样的,读入数据存在数组int a[80][80]中。
二、初始化标记和优先队列
m[0][0] = 2;
m[1][0] = 1;
m[0][1] = 1;
b[0][0] = a[0][0];
b[0][1] = b[0][0] + a[0][1];
b[1][0] = b[0][0] + a[1][0];
pq[0] = &b[0][1];
pq[1] = &b[1][0];
end = 2;
标记数组m[80][80]储存的是该点位的状态。2为已解出到开始点的最短路径。1为已解出其相邻点
到开始点的最短路径。0为其它。
数组b[80][80]储存的是计算到当前该店到开始点的最短距离。具体是不是最终值取决于m值。
优先队列pq的定义是
int *pq[10000] ,start = 0, end = 0;
本质上就是一个指针数组,存的是数组b中的一些元素的地址。如果你想问我是怎么实现优先的,我会告诉你是在每次取值之前使用qsort先排个序~相对于使用堆的确会对时间复杂度产生影响,但这道题的时间还是够用的~并且写个堆也挺麻烦的~STL中的priortyqueue也没那么好用...并且不是说好的是纯c风格的代码么...
三、不断地从优先队列中取值,标记,并在终止点的最短路径被计算出来的时候终止。
for (int Z = 0; Z < 6399; Z++)
{
qsort(pq + start, end-start, sizeof(int *),comp);
int px = (pq[start] - b[0])/80;
int py = (pq[start] - b[0])%80;
if (px > 0)
Do(px - 1, py, *pq[start]);
if (px < 79)
Do(px + 1, py, *pq[start]);
if (py > 0)
Do(px, py - 1, *pq[start]);
if (py < 79)
Do(px, py + 1, *pq[start]);
start++;
m[px][py] = 2;
if (m[79][79] == 2)
{
ans = b[79][79];
break;
}
}
px和py的运算时根据二原数组的元素纯粹地址的规律计算从优先队列中取出的元素在b中的位置。
函数Do:
void Do(int px, int py, int d)
{
if (m[px][py] == 2)
return;
if (m[px][py] == 1)
{
if (a[px][py] + d < b[px][py])
b[px][py] = a[px][py] + d;
return;
}
if (m[px][py] == 0)
{
b[px][py] = a[px][py] + d;
m[px][py] = 1;
pq[end] = &b[px][py];
end++;
return;
}
}
完成标记工作。(这几个数组我设的是全局变量,方便起见~)
而qsort的比较函数comp为:
int comp(const void * a, const void * b)
{
return **(int **)a - **(int **)b;
}
最终,输出的答案为425185。
以上只是我做题时的解法。
如果有更好的解法、更好的思路,欢迎评论讨论~O(∩_∩)O~