最优对称路径

5 篇文章 0 订阅
5 篇文章 0 订阅
湖南省第七届大学生计算机程序设计竞赛 The Seventh Hunan Collegiate Programming Contest
题目G
最优对称路径

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


你的任务是统计所有合法路径中,数字之和最小的路径有多少条。
输入
输入最多包含25组测试数据。每组数据第一行为一个整数n(2<=n<=100)。以下n行每行包含n个1到9的数字,表示输入网格。输入结束标志为n=0。
输出
对于每组数据,输出合法路径中,数字之和最小的路径条数除以1,000,000,009的余数。
样例输入
2
1 1
1 1
3
1 1 1
1 1 1
2 1 1
0

样例输出

2
3


可以按对角线折过来,然后最短路的求法,从(1,1)到对角线所有的点的最短路求出来,有点类似于SPFA,把每个更新过的点加入队列去做扩展,选出其中最小的路

然后从对角线上的点一个个选满足是最短的,然后从这些点中dfs找出所有的路线,这里对于找过的路要标记一下用来剪支

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#define inf 10000
#define maxn 1000000009
using namespace std;
int matrix[205][205];
int d[205][205];
queue<int> q;
int nx[]={1,0,0,-1};
int ny[]={0,-1,1,0};
int down[205][205];
int dp[205][205];
bool flag[205][205];
int n;
int check(int x,int y)
{
    if(x>0&&y>0&&x<=n&&y<=n-x+1)
    return 1;
    return 0;
}
int dfs(int x,int y)
{
   // printf("~~~%d %d\n",x,y);
    if(flag[x][y])
    return dp[x][y];
    flag[x][y]=1;
    for(int i=0;i<4;i++)
    {
        int ax=x+nx[i];
        int ay=y+ny[i];
        if(check(ax,ay)&&d[x][y]==matrix[x][y]+d[ax][ay])
        dp[x][y]=(dp[x][y]%maxn+dfs(ax,ay)%maxn)%maxn;
    }
    return dp[x][y]%maxn;
}
int main()
{
    while(scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        scanf("%d",&matrix[i][j]);
        int sign=n;
        memset(down,0,sizeof(down));
        memset(dp,0,sizeof(dp));
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++,sign--)
        {
            for(int j=1;j<sign;j++)
            {
                matrix[i][j]+=matrix[n-j+1][n-i+1];
            }
        }
        sign=n;
        for(int i=1;i<=n;i++,sign--)
        {
            for(int j=1;j<=sign;j++)
            {
               d[i][j]=inf;
            }
        }
        q.push(1);
        q.push(1);
        d[1][1]=matrix[1][1];
        while(!q.empty())
        {
            int dx=q.front();
            q.pop();
            int dy=q.front();
            q.pop();
            down[dx][dy]=0;
           // printf("~~~%d %d\n",dx,dy);
            for(int i=0;i<4;i++)
            {
                int mx=dx+nx[i];
                int my=dy+ny[i];
               if(check(mx,my)&&d[mx][my]>d[dx][dy]+matrix[mx][my])
                {
                   // printf("!!%d %d\n",mx,my);
                    d[mx][my]=d[dx][dy]+matrix[mx][my];
                    if(down[mx][my]==0)
                    {
                        down[mx][my]=1;
                        q.push(mx);
                        q.push(my);
                    }
                }
            }
        }//SPFA
        int mins=10000;
        for(int i=1,j=n;i<=n&&j>0;i++,j--)
        if(d[i][j]<mins)
        mins=d[i][j];
        int path=0;
        dp[1][1]=1;
        for(int i=1,j=n;i<=n&&j>0;i++,j--)
        if(d[i][j]==mins)
        path=(path%maxn+dfs(i,j)%maxn)%maxn;
        printf("%d\n",path);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值