湖南省第七届省赛 G - 最优对称路径(spfa+dp)

来源:互联网 发布:最早睡直播软件 编辑:程序博客网 时间:2024/05/30 19:34

G - 最优对称路径
Time Limit:1000MS Memory Limit:131072KB 64bit IO Format:%lld & %llu
Submit Status

Description
给一个n行n列的网格,每个格子里有一个1到9的数字。你需要从左上角走到右下角,其中每一步只能往上、下、左、右四个方向之一走到相邻格子,不能斜着走,也不能走出网格,但可以重复经过一个格子。为了美观,你经过的路径还必须关于“左下-右上”这条对角线对称。下图是一个6x6网格上的对称路径。
你的任务是统计所有合法路径中,数字之和最小的路径有多少条。

Input

输入最多包含25组测试数据。每组数据第一行为一个整数n(2<=n<=200)。以下n行每行包含n个1到9的数字,表示输入网格。输入结束标志为n=0。

Output

对于每组数据,输出合法路径中,数字之和最小的路径条数除以1,000,000,009的余数。

Sample Input

2
1 1
1 1
3
1 1 1
1 1 1
2 1 1
0

Sample Output

2
3

这道题因为我们要求满足提意的路径,这个路径需要满足下列条件

 1. 对称 2. 最短的

这两个限制是我们需要考虑的。
首先,我们如何求出来的路径是对称的,我们只需要把这个正方形对折就行了(注意题目给的条件,n*n),这样,我们从(0,0)到对角线的距离肯定是对称的。
然后我们考虑怎么样是最短的,我们只需要spfa首先预处理出(0,0)到所有点的最短距离就行了。
最后,我们统计方案数,统计的时候我们使用记忆化dp,我们仅仅统计在最短路上的路径就行了。

#include<cstdio>#include<cstring>#include<vector>#include<iostream>using namespace std;#include<queue>const long long mod=1000000009LL;const int maxn=205;const int inf=0x3f3f3f3f;int a[maxn][maxn];int d[maxn][maxn];int n;long long dp[maxn][maxn];int der[4][2]= {{0,1},{1,0},{0,-1},{-1,0}};int minans;void spfa() {    memset(d,inf,sizeof(d));    queue<int> que;    while(!que.empty()) {        que.pop();    }    que.push(0);    d[0][0]=a[0][0];    while(!que.empty()) {        int now=que.front();        que.pop();        for(int i=0; i<4; ++i) {            int tx=der[i][0]+now/maxn;            int ty=der[i][1]+now%maxn;            if(tx>=0&&tx<n&&ty>=0&&ty<n&&d[tx][ty]>d[now/maxn][now%maxn]+a[tx][ty]) {                d[tx][ty]=d[now/maxn][now%maxn]+a[tx][ty];                que.push(tx*maxn+ty);            }        }    }    minans=inf;    for(int i=0; i<n; ++i) {        for(int j=0; j<n; ++j) {            if(i+j==n-1) {                minans=min(minans,d[i][j]);            }        }    }}long long dfs(int nowx,int nowy) {    if(dp[nowx][nowy]^-1)        return dp[nowx][nowy];    if(nowx+nowy==n-1)        return dp[nowx][nowy]=(minans==d[nowx][nowy]);    dp[nowx][nowy]=0;    for(int i=0; i<4; ++i) {        int tx=nowx+der[i][0];        int ty=nowy+der[i][1];        if(tx>=0&&tx<n&&ty>=0&&ty<n&&(d[nowx][nowy]+a[tx][ty]==d[tx][ty])) {            dp[nowx][nowy]+=dfs(tx,ty);            dp[nowx][nowy]%=mod;        }    }    dp[nowx][nowy]%=mod;    return dp[nowx][nowy];}int main() {    while(~scanf("%d",&n),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-i-1; ++j) {                a[i][j]+=a[n-j-1][n-i-1];            }        }        spfa();        memset(dp,-1,sizeof(dp));        printf("%d\n",dfs(0,0));    }    return 0;}
1 0