UVA_12295
首先我们可以把线的两边对折,这样就变成了半个矩阵,同时问题就转化成了从左上角到折线的位置的最短路径的条数有多少。
首先,我们可以用SPFA求单源最短路,这样起点到每个点的最短路就都有了。之后为了能够算出路径的条数,我们可以从起点开始,每次取栈中d[]的值最小的点出栈,然后按最短路径的走向向周围的点拓展,并将拓展成功的点入栈。
最后,统计折线上的最短路的最小值,并把所有符合要求的路径的条数相加即可。
这个题目用dij及优先级队列做会更简单、高效,等学完dij之后再回头做下这个题目。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 110
#define MAXD 10010
#define INF 1000000000
#define MOD 1000000009
int N, a[MAXN][MAXN];
long long int f[MAXD];
int q[MAXD], inq[MAXD], d[MAXD], min;
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int cmp(const void *_p, const void *_q)
{
int *p = (int *)_p;
int *q = (int *)_q;
return d[*q] - d[*p];
}
int init()
{
int i, j;
scanf("%d", &N);
if(!N)
return 0;
for(i = 0; i < N; i ++)
for(j = 0; j < N; j ++)
scanf("%d", &a[i][j]);
for(i = 0; i < N; i ++)
for(j = 0; j < N - i - 1; j ++)
a[i][j] += a[N - 1 - j][N - 1 - i];
return 1;
}
void SPFA()
{
int i, j, k, z, newz, x, y, newx, newy, front, rear;
for(i = 0; i < MAXD; i ++)
d[i] = INF;
d[0] = a[0][0];
memset(inq, 0, sizeof(inq));
front = rear = 0;
q[rear ++] = 0;
while(front != rear)
{
z = q[front ++];
if(front > N * N)
front = 0;
inq[z] = 0;
x = z / N;
y = z % N;
if(x + y == N - 1)
continue;
for(i = 0; i < 4; i ++)
{
newx = x + dx[i];
newy = y + dy[i];
if(newx >= 0 && newx < N && newy >= 0 && newy < N)
{
newz = newx * N + newy;
if(d[z] + a[newx][newy] < d[newz])
{
d[newz] = d[z] + a[newx][newy];
if(!inq[newz])
{
q[rear ++] = newz;
if(rear > N * N)
rear = 0;
inq[newz] = 1;
}
}
}
}
}
}
void DP()
{
int i, j, k, top, z, x, y, newx, newy, newz;
top = 0;
memset(f, 0, sizeof(f));
memset(inq, 0, sizeof(inq));
f[0] = 1;
inq[0] = 1;
q[top ++] = 0;
while(top)
{
z = q[-- top];
x = z / N, y = z % N;
if(x + y == N - 1)
continue;
for(i = 0; i < 4; i ++)
{
newx = x + dx[i];
newy = y + dy[i];
if(newx >= 0 && newx < N && newy >= 0 && newy < N)
{
newz = newx * N + newy;
if(d[newz] == d[z] + a[newx][newy])
{
f[newz] = (f[newz] + f[z]) % MOD;
if(!inq[newz])
{
inq[newz] = 1;
q[top ++] = newz;
}
}
}
}
qsort(q, top, sizeof(q[0]), cmp);
}
}
void solve()
{
int i, j, k;
long long int ans;
SPFA();
DP();
min = INF;
for(i = 0; i < N; i ++)
if(d[i * N + N - 1 - i] < min)
min = d[i * N + N - 1 - i];
ans = 0;
for(i = 0; i < N; i ++)
if(d[i * N + N - 1 - i] == min)
ans = (ans + f[i * N + N - 1 - i]) % MOD;
printf("%lld\n", ans);
}
int main()
{
while(init())
{
solve();
}
return 0;
}