题意:求(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