zoukankan      html  css  js  c++  java
  • 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;
    }




  • 相关阅读:
    c++ time_t
    sql 一些题目
    vc 找到一个或多个多重定义的符号
    c++ json 详解
    c++ json cpp
    C++ string(转)
    java web 复选框checked
    20_采用ContentProvider对外共享数据
    16_采用SharedPreferences保存用户偏好设置参数
    android开发 eclipse alt+”/”自动提示失效
  • 原文地址:https://www.cnblogs.com/staginner/p/2248567.html
Copyright © 2011-2022 走看看