ACM学习历程—广东工业大学2016校赛决赛-网络赛C wintermelon的魔界寻路之旅(最短路 && 递推)

题目链接:http://gdutcode.sinaapp.com/problem.php?cid=1031&pid=2

题目由于要找对称的路径,那么狠明显可以把右下角的每一块加到左上角对应的每一块上。然后就变成从左上角走到对角线的最短路径的个数。

先跑一遍最短路径得到p(i, j)从起点到(i, j)的最短路径。

然后就是找最短路径的个数。显然cnt(i, j)是它周围点能通过最短路径到它的cnt的和。这一处可以使用记忆化搜索来完成。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long
#define MOD 1000000009

using namespace std;

const int maxN = 105;
int xx[] = {-1,  1,  0,  0};
int yy[] = { 0,  0, -1,  1};
int n, a[maxN][maxN], mi;
int p[maxN][maxN];
int cnt[maxN][maxN];
bool vis[maxN*maxN];

void input()
{
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            scanf("%d", &a[i][j]);
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            if (i+j != n-1)
                a[i][j] += a[n-1-j][n-1-i];
    memset(p, -1, sizeof(p));
    memset(vis, false, sizeof(vis));
}

void cal()
{
    int k, x, y, ix, iy;
    queue<int> q;
    p[0][0] = a[0][0];
    q.push(0);
    vis[0] = true;
    while (!q.empty())
    {
        k = q.front();
        q.pop();
        vis[k] = false;
        x = k/100;
        y = k%100;
        for (int i = 0; i < 4; ++i)
        {
            ix = x+xx[i];
            iy = y+yy[i];
            if (ix+iy > n-1 || ix < 0 || iy < 0) continue;
            if (p[ix][iy] == -1 || p[ix][iy] > p[x][y]+a[ix][iy])
            {
                p[ix][iy] = p[x][y]+a[ix][iy];
                if (!vis[100*ix+iy])
                {
                    q.push(100*ix+iy);
                    vis[100*ix+iy] = true;
                }
            }
        }
    }
    mi = p[0][n-1];
    for (int i = 0; i < n; ++i)
        mi = min(mi, p[i][n-1-i]);
}

int dfs(int x, int y)
{
    if (cnt[x][y] != -1) return cnt[x][y];
    int ix, iy, all = 0;
    for (int i = 0; i < 4; ++i)
    {
        ix = x+xx[i];
        iy = y+yy[i];
        if (ix+iy > n-1 || ix < 0 || iy < 0) continue;
        if (p[ix][iy]+a[x][y] == p[x][y])
            all = (all+dfs(ix, iy))%MOD;
    }
    cnt[x][y] = all;
    return all;
}

void work()
{
    cal();
    memset(cnt, -1, sizeof(cnt));
    cnt[0][0] = 1;
    int ans = 0;
    for (int i = 0; i < n; ++i)
        if (mi == p[i][n-1-i])
            ans = (ans+dfs(i, n-1-i))%MOD;
    printf("%d
", ans);
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T;
    scanf("%d", &T);
    for (int times = 1; times <= T; ++times)
    {
        input();
        work();
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/andyqsmart/p/5375151.html