UVA - 12295 最短路+递推

有一个n*n的矩阵,要求从(1,1)到(n,n)的最短路数量,路径的权值是所经过元素的和,且路径与对角线对称。

由于路径是对称的,可以先预处理将右下角的元素加到左上角,那么就只用计算(1,1)到对角线的最短路数量了,计算最短路可以用dijkstra,要计算数量只需要在dijkstra的过程中递推一下就好了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e2+5;
const int mod=1e9+9;
const int inf=0x3f3f3f3f;
int zu[maxn][maxn],n;
int dis[maxn][maxn],num[maxn][maxn];
bool mark[maxn][maxn];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
void dijkstra()
{
    memset(mark,false,sizeof(mark));
    memset(dis,inf,sizeof(dis));
    memset(num,0,sizeof(num));
    dis[1][1]=zu[1][1],num[1][1]=1;
    int lim=(n*n-n)/2,cnt=0;
    while(cnt++<lim)
    {
        int r,c,d=inf;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n-i;j++)
            {
                if(!mark[i][j]&&dis[i][j]<d)
                {
                    d=dis[i][j];
                    r=i,c=j;
                }
            }
        }
        mark[r][c]=true;
        for(int i=0;i<4;i++)
        {
            int rr=r+dir[i][0],cc=c+dir[i][1];
            if(rr<1||rr>n||cc<1||cc>n) continue;
            if(dis[rr][cc]>dis[r][c]+zu[rr][cc])
            {
                dis[rr][cc]=dis[r][c]+zu[rr][cc];
                num[rr][cc]=num[r][c]%mod;
            }
            else if(dis[rr][cc]==dis[r][c]+zu[rr][cc])
                num[rr][cc]=(num[rr][cc]+num[r][c])%mod;
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=-1)
    {
        if(n==0) break;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&zu[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n-i;j++)
                zu[i][j]+=zu[n-j+1][n-i+1];
        dijkstra();
        int mindis=inf;
        for(int i=1;i<=n;i++)
            mindis=min(mindis,dis[i][n-i+1]);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(dis[i][n-i+1]==mindis)
                ans=(ans+num[i][n-i+1])%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值