题意:从左上角到右下角找出来最短的路有几条,并且路线一定要与副对角线对称
思路:既然要求与副对角线对称并且起点是左上角终点是右下角,那么我们可以把以副对角线为准的先半部分重叠到上半部分,也就是把下半部分加到上半部分。这是我们只要从上半部分出发只要走到副对角线我们就算走到了原图的右下角。我们可以使用最短路spfa来求这个最短路,然后先查找最短距离是哪个,再看这个最短距离有几个。不过建图挺麻烦的。要使用spfa就得把每个点重新编号。代码最后还有一组样例,可以测试一下自己的程序。
#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> using namespace std; #define inf 0x3f3f3f3f const int mod=1000000009; int mapp[105][105]; int dis[10005]; int num[10005];//记录方案数 int vis[10005]; int first[10005]; struct node { int to; int cost; int next; } e[1000005]; int dx[4]= {0,0,-1,1}; int dy[4]= {-1,1,0,0}; int r,n; void add(int x,int y,int cost) { e[r].to=y; e[r].cost=cost; e[r].next=first[x]; first[x]=r++; } int spfa(int s) { queue<int>q; memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); q.push(s); vis[s]=1; dis[s]=0; num[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=first[u]; i!=-1; i=e[i].next) { int v=e[i].to; if(dis[v]>dis[u]+e[i].cost) { dis[v]=dis[u]+e[i].cost;//如果可以更新,那么代表num的路径数跟上个点一样,从一条路过来 num[v]=num[u]; if(vis[v]==0) { vis[v]=1; q.push(v); } } else if(dis[v]==dis[u]+e[i].cost)//相等就代表可以找到新的路 { num[v]=(num[v]+num[u])%mod; } } } } int solve() { r=0; memset(first,-1,sizeof(first)); for(int i=0; i<n-1; i++)//叠加 { for(int j=0; j<n-i-1; j++) { mapp[i][j]+=mapp[n-1-j][n-1-i]; } } for(int i=0; i<n; i++)//重新建图 { for(int j=0; j<n-i; j++) { for(int k=0; k<4; k++) { int nx=i+dx[k]; int ny=j+dy[k]; if(nx>=0&&ny>=0&&nx+ny<=n-1) { add(i*n+j,nx*n+ny,mapp[nx][ny]);//i*n+j和nx*n+ny是为了给点重新编号 } } } } spfa(0); int res=inf; int i=0,j=n-1; while(j>=0)//先找到最短的距离是多少 { res=min(res,dis[i*n+j]); i++; j--; } int ans=0; i=0; j=n-1; while(j>=0)//看这个距离有多少个 { if(res==dis[i*n+j]) ans=(ans+num[i*n+j])%mod; i++; j--; } printf("%d\n",ans); } int main() { while(~scanf("%d",&n)) { if(n==0) break; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) scanf("%d",&mapp[i][j]); } solve(); } } //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