UVA - 12295 Optimal Symmetric Paths(spfa)

本文介绍了一种算法,用于计算从起点(1,1)到终点(n,n)的对称最短路径数量。该算法通过对右下角的值进行对称处理并加入到左上角对应的值中来简化问题,利用SPFA算法找到最短路径及其数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



题意:求(1,1)到(n,n)点的路径中有多少条为最短路径,而且行走的路径要以对角线对称;

解 :我们可以先以对角线为对称,把右下的值加到对称的左上的值中,然后从(1,1)走到对角线就行,而且我们可以让对角线所有点和ed点加上1条路径,长度为0。   

我们让左上及对角线上的点逐一编号,而且把临近的两个点建边 每个点有两个值 dis[i] (代表最短距离)和pp[i](代表最短路径的数量),最后我们得到pp[ed]%mod即可

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const ll mod=1000000009;
int n,tot,num,ed;
int d[1100][1010];
int p[30000];
ll dis[30000];//最短距离
ll pp[30000];//最短距离个数
int vis[30000];
int a[1010][1100];
struct node
{
    int en,next;
    ll w;
}e[10000000];
void add(int u,int v,ll w)
{
    e[tot].en=v;
    e[tot].next=p[u];
    e[tot].w=w;
    p[u]=tot++;
}
int go(int x,int y)
{
    if(0>=x||x>n||0>=y||y>n)
        return 0;
    if(x+y>n+1)
        return 0;
    return 1;
}
void kk(int x,int y)//建图
{
    if(go(x-1,y)&&a[x-1][y])
        add(a[x][y],a[x-1][y],d[x][y]);
    if(go(x+1,y)&&a[x+1][y])
        add(a[x][y],a[x+1][y],d[x][y]);
    if(go(x,y-1)&&a[x][y-1])
        add(a[x][y],a[x][y-1],d[x][y]);
    if(go(x,y+1)&&a[x][y+1])
        add(a[x][y],a[x][y+1],d[x][y]);

}
void spfa()
{
  queue<int>q;
  memset(dis,inf,sizeof(dis));
  memset(vis,0,sizeof(vis));
  memset(pp,0,sizeof(pp));
  pp[1]=1;
  dis[1]=0;
  vis[1]=1;
  q.push(1);
  while(!q.empty())
  {
      int x=q.front();
      q.pop();
      vis[x]=0;
      for(int i=p[x];i+1;i=e[i].next)
      {
             int kk=e[i].en;
              if(dis[kk]>dis[x]+e[i].w)
              {
              dis[kk]=dis[x]+e[i].w;
              pp[kk]=pp[x]%mod;;
              if(vis[kk])
                continue;
              q.push(kk);
              vis[kk]=1;
              }
              else if(dis[kk]==dis[x]+e[i].w)//一样则加上
               pp[kk]=(pp[kk]+pp[x])%mod;
              
      }
  }
}
int main()
{
   while(~scanf("%d",&n)&&n)
   {
       ed=20000;
       memset(p,-1,sizeof(p));
       memset(a,0,sizeof(a));
       num=0;
       tot=0;
       for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
         scanf("%d",&d[i][j]);
       for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
           {
               if(i+j<n+1)
               {
                d[i][j]+=d[n+1-j][n+1-i];
                a[i][j]=++num;
               }
               if(i+j==n+1)
               {
                   a[i][j]=++num;
                   add(num,ed,d[i][j]);
               }
           }
           for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
               if(i+j<n+1)
                   kk(i,j);
        spfa();
        printf("%lld\n",pp[ed]);
   }
}

5
1 9 1 1 1
1 1 1 9 1
9 9 9 1 1
9 9 9 1 9

9 9 9 1 1

1






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值