• UVA 12295 Optimal Symmetric Paths


    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;
    }




  • 相关阅读:
    splinter webdriver API 的基本实现
    201253 线程和进程的区别
    Winform中的默认图片
    [收藏】正确使用SqlConnection对象,兼谈数据库连接池
    手机相关的基础名称
    常见排序
    SIP相关内容
    How to set the WIFI configuration
    本地化的设置和读取
    Serialize And Deserialize Binary Tree
  • 原文地址:https://www.cnblogs.com/staginner/p/2248567.html
Copyright © 2020-2023  润新知