路径数
题目描述
Euphemia到一个\(N*N\)的药草田里采药,她从左上角的格子田(第一行,第一列)出发,要到达右下角(第\(N\)行,第\(N\)列)的格子田,每次她可以走到与当前格子有边相邻的格子去,但她不会走已经走过的格子,而且出于对美的要求,她走过的路径是关于 左下-右上 对角线对称的。由于地势不同,在每个格子田采药都会有一个疲劳度\(T_{i,j}\),Euphemia想知道:有多少条合法路径,可以使得她采药的疲劳度最小。
输入格式:
多组数据。
每组数据第一行一个整数\(N\),接下来\(N\)行,每行$N4个非零数字(\(1,2,3...9\)中一个),表示格子田的疲劳度。
当\(N=0\),输入结束。
输出格式:
对于每组数据,输出一个整数表示答案,答案%1000000009。
样例输入:
2 1 1 1 1 3 1 1 1 1 1 1 2 1 1 0
样例输出:
2 3
数据范围:
对于\(20%\)的数据满足\(N<=5\)。
对于另外\(20%\)的数据满足\(N<=40\)。
对于\(100%\)的数据满足\(N<=100\),不超过\(50\)组数据。
时间限制:
1S
空间限制:
256M
提示:
remove!!!
题解
根据题意可知这是一道图论题。
求最短路径的方案数。
因为她走过的路径是关于 左下-右上 对角线对称的所以我们可以把这个矩阵沿 左下-右上 对角线“对折”下来。
接下来在剩下的“三角形图”上跑dijstra求最短路,并且松弛的时候记录一下方案数就好了。
最后在对角线上统计一下最短路的方案数。
dijstra加上堆优化,时间复杂度是\((N^3)\)(节点数为\(N^2\))。
上代码:
#include<bits/stdc++.h> #include<queue> #define mod 1000000009 using namespace std; int n; int a[109][109]; int dis[109][109],s[109][109]; bool k[109][109]; int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; void dij(int x,int y){ priority_queue< pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pp; dis[1][1]=a[1][1]; s[1][1]=1; pp.push(make_pair(dis[x][y],x*n+y-1)); while(!pp.empty()){ pair<int,int> u=pp.top(); pp.pop(); int y=u.second%n+1,x=u.second/n; // printf("*%d %d*\n",x,y); if(k[x][y]) continue; k[x][y]=1; for(int j=0;j<4;j++){ int xx=x+dir[j][0],yy=y+dir[j][1]; if(xx<1 || yy<1 || xx+yy>n+1 || k[xx][yy]) continue; // printf("!%d %d!\n",xx,yy); if(dis[xx][yy]==-1 || dis[xx][yy]>dis[x][y]+a[xx][yy]){ dis[xx][yy]=dis[x][y]+a[xx][yy]; s[xx][yy]=s[x][y]; pp.push(make_pair(dis[xx][yy],xx*n+yy-1)); } else if(dis[xx][yy]==dis[x][y]+a[xx][yy]) s[xx][yy]+=s[x][y]; } } } int main() { while(1){ scanf("%d",&n); if(n==0) break; memset(dis,-1,sizeof(dis)); memset(s,0,sizeof(s)); memset(a,0,sizeof(a)); memset(k,0,sizeof(k)); for(int j=1;j<=n;j++) for(int i=1;i<=n;i++) scanf("%d",&a[j][i]); for(int j=1;j<=n;j++) for(int i=n-j+2;i<=n;i++) a[n-i+1][n-j+1]+=a[j][i]; dij(1,1); int mn=-1,ss; for(int j=1;j<=n;j++){ // printf("**%d %d %d**\n",j,dis[j][n-j+1],s[j][n-j+1]); if(mn==-1 || mn>dis[j][n-j+1]){ mn=dis[j][n-j+1]; ss=s[j][n-j+1]; } else if(mn==dis[j][n-j+1]) ss+=s[j][n-j+1]; } printf("%d\n",ss); } return 0; }