UVA_12295

    之前最早使用SPFA+qsort实现的优先队列写的这个题目,今天又重新用不同的方式写了一遍这个题目,即SPFA+手写堆实现的优先队列,SPFA+记忆化搜索,在Dij的过程中顺便记录路径条数等这样三种方式。

    写完之后,和预想的一样SPFA+手写堆实现的优先队列是最慢的,但对于剩下两个写法感觉得到的结论和网上看到的一篇文章写的不太一样,他说对于网格类数据Dij要明显比SPFA快一些,但就我的测试结果来看,实际上SPFA最后再加一个记忆化搜索所需的时间都要比Dij更快一些(Dij只是顺便记录了路径条数)。当然,也有可能是我自己写的堆优化的Dij效率比较低,而且我在本地用的是1000组N为100的符合题意的随机数据测的,因此也有可能SPFA更擅长处理随机数据?

 

//SPFA+手写堆实现的优先队列
#include<stdio.h>
#include<string.h>
#define MAXN 110
#define MAXD 10010
#define INF 1000000000
#define MOD 1000000009
int N, M, a[MAXN][MAXN];
long long int f[MAXD];
int q[MAXD], inq[MAXD], d[MAXD], vis[MAXD], min, tree[4 * MAXD];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
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[1] = a[0][0];
memset(inq, 0, sizeof(inq));
front = rear = 0;
q[rear ++] = 1;
while(front != rear)
{
z = q[front ++];
if(front > N * N)
front = 0;
inq[z] = 0;
x = (z - 1) / N;
y = (z - 1) % 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 + 1;
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 insert(int x)
{
int i = x + M;
tree[i] = x;
for(; i ^ 1; i >>= 1)
tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void del(int x)
{
int i = x + M;
tree[i] = 0;
for(; i ^ 1; i >>= 1)
tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void DP()
{
int i, j, k, z, x, y, newx, newy, newz;
memset(f, 0, sizeof(f));
memset(tree, 0, sizeof(tree));
memset(vis, 0, sizeof(vis));
for(M = 1; M < N * N + 2; M <<= 1);
f[1] = 1;
insert(1);
for(; tree[1];)
{
z = tree[1];
x = (z - 1) / N;
y = (z - 1) % N;
del(z);
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 + 1;
if(d[z] + a[newx][newy] == d[newz])
{
f[newz] += f[z];
if(!vis[newz])
{
vis[newz] = 1;
insert(newz);
}
}
}
}
}
}
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 - i] < min)
min = d[i * N + N - i];
ans = 0;
for(i = 0; i < N; i ++)
if(d[i * N + N - i] == min)
ans = (ans + f[i * N + N - i]) % MOD;
printf("%lld\n", ans);
}
int main()
{
while(init())
{
solve();
}
return 0;
}

 

//SPFA+记忆化搜索
#include<stdio.h>
#include<string.h>
#define MAXN 110
#define MAXD 10010
#define INF 1000000000
#define MOD 1000000009
int N, M, a[MAXN][MAXN];
long long int f[MAXD];
int q[MAXD], inq[MAXD], d[MAXD], vis[MAXD], min, tree[4 * MAXD];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
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[1] = a[0][0];
memset(inq, 0, sizeof(inq));
front = rear = 0;
q[rear ++] = 1;
while(front != rear)
{
z = q[front ++];
if(front > N * N)
front = 0;
inq[z] = 0;
x = (z - 1) / N;
y = (z - 1) % 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 + 1;
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;
}
}
}
}
}
}
long long int DP(int cur)
{
int i, x, y, newx, newy, newz;
if(f[cur] != -1)
return f[cur];
x = (cur - 1) / N;
y = (cur - 1) % N;
if(x + y == N - 1)
{
if(d[cur] == min)
f[cur] = 1;
else
f[cur] = 0;
return f[cur];
}
f[cur] = 0;
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 + 1;
if(d[cur] + a[newx][newy] == d[newz])
f[cur] += DP(newz);
}
}
return f[cur];
}
void solve()
{
int i, j, k;
long long int ans;
SPFA();
min = INF;
for(i = 0; i < N; i ++)
if(d[i * N + N - i] < min)
min = d[i * N + N - i];
memset(f, -1, sizeof(f));
ans = DP(1);
printf("%lld\n", ans);
}
int main()
{
while(init())
{
solve();
}
return 0;
}

 

//在Dij过程中顺便记录路径条数
#include<stdio.h>
#include<string.h>
#define MAXN 110
#define MAXD 10010
#define INF 1000000000
#define MOD 1000000009
int N, M, a[MAXN][MAXN];
long long int f[MAXD];
int q[MAXD], inq[MAXD], d[MAXD], min, tree[4 * MAXD];
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
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 insert(int x)
{
int i = x + M;
tree[i] = x;
for(; i ^ 1; i >>= 1)
tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void del(int x)
{
int i = x + M;
tree[i] = 0;
for(; i ^ 1; i >>= 1)
tree[i >> 1] = d[tree[i]] < d[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void dij()
{
int i, j, k, z, x, y, newx, newy, newz;
memset(f, 0, sizeof(f));
memset(tree, 0, sizeof(tree));
for(M = 1; M < N * N + 2; M <<= 1);
f[1] = 1;
for(i = 0; i < MAXD; i ++)
d[i] = INF;
d[1] = a[0][0];
insert(1);
for(; tree[1];)
{
z = tree[1];
x = (z - 1) / N;
y = (z - 1) % N;
del(z);
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 + 1;
if(d[z] + a[newx][newy] < d[newz])
{
d[newz] = d[z] + a[newx][newy];
f[newz] = f[z];
insert(newz);
}
else if(d[z] + a[newx][newy] == d[newz])
f[newz] += f[z];
}
}
}
}
void solve()
{
int i, j, k;
long long int ans;
dij();
min = INF;
for(i = 0; i < N; i ++)
if(d[i * N + N - i] < min)
min = d[i * N + N - i];
ans = 0;
for(i = 0; i < N; i ++)
if(d[i * N + N - i] == min)
ans = (ans + f[i * N + N - i]) % MOD;
printf("%lld\n", ans);
}
int main()
{
while(init())
{
solve();
}
return 0;
}




posted on 2011-11-14 16:18  Staginner  阅读(283)  评论(0编辑  收藏  举报