路径数
题目描述
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求最短路,并且松弛的时候记录一下方案数就好了。
最后在对角线上统计一下最短路的方案数。
dijkstra加上堆优化,时间复杂度是\((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;
}