UVA 12295

6 篇文章 0 订阅
3 篇文章 0 订阅


题意:给你一个矩阵,按照副对角线对称的路径从(0,0)走到(n-1,n-1)的最小价值的路径数;

矩阵的每一个点aij代表价值;


思路:将矩阵的下半部加到上半部,这样只要走到副对角线即可;

先SPFA求d[i][j]表示走到i,j这个点的最小价值,得到d[i][n-i-1]的价值,

找出最小价值minn的点(i,n-i-1),从这个点回溯到(0,0)求出有多少路径,即为答案。


#include <stdio.h>  
#include <string.h>  
#include <vector>  
#include <queue>  
#include <algorithm>  
#include <iostream>
using namespace std;  

#define N 1005  
#define INF 1000000000
#define MOD 1000000009  
int m[4][2]={-1,0,0,1,1,0,0,-1};
int n,mat[105][105];
struct node
{
	int x,y,dis;
	friend bool operator<(node a,node b)  
	{  
		return a.dis > b.dis;  
	}  
};
bool Isok(int x,int y)
{
	if(x>=0&&x<n&&y>=0&&y<n&&(x+y)<n) return true;
	return false;
}

int vis[105][105],d[105][105];
void SPFA()//初始d[i][j]
{
	memset(vis,0,sizeof(vis));
	int i, j, dx, dy;
	for (i = 0; i < n; i++)
		for (j = 0; j < n-i; j++)
			d[i][j] = INF;
	node p,q;
	d[0][0]=mat[0][0];
	p.x=0;p.y=0;p.dis=mat[0][0];
	priority_queue<node>Q;
	Q.push(p);
	while(!Q.empty())
	{
		q=Q.top();
		Q.pop();
		if(vis[q.x][q.y])
			continue; 
		vis[q.x][q.y]=1;
		for (i=0;i<4;i++)
		{
		    dx=q.x+m[i][0];
			dy=q.y+m[i][1];
			if(!Isok(dx,dy))
				continue;
			if(d[dx][dy]-mat[dx][dy]>q.dis)
			{
				d[dx][dy]=mat[dx][dy]+q.dis;
				p.x=dx;p.y=dy;p.dis=d[dx][dy];
				Q.push(p);
			}
		}
	}

}

int dfs(int x,int y)
{
	int res=0;
	if(x==0&&y==0)//搜到(0,0),则找到一条路径;
		return 1;
	for(int i=0;i<4;i++)
	{
	    int dx=x+m[i][0];
		int dy=y+m[i][1];
		if(!Isok(dx,dy))
			continue;
		if(d[x][y]==d[dx][dy]+mat[x][y])//关键:要满足(x,y)的上一点是(dx,dy)
		    res=(res+dfs(dx,dy))%MOD;
	}
	return res;
}
int main()
{
	while(scanf("%d", &n))
	{
		if(n==0) break;
		int i,j;
		for (i = 0;i < n; i++)
			for (j = 0;j < n;j++)
				scanf("%d", &mat[i][j]);
		for (i = 0; i < n; i++)
			for (j = 0; j < n-i-1; j++)
				mat[i][j] += mat[n-j-1][n-i-1];
		SPFA();
		int minn=INF;
		int ans=0;
		for(i=0;i<n;i++)
			if(d[i][n-i-1]<minn)
				minn=d[i][n-i-1];//找出最小的价值;
		for(i=0;i<n;i++)
			if(d[i][n-i-1]==minn)//从最小的价值往回搜
				ans=(ans+dfs(i,n-i-1))%MOD;
		printf("%d\n",ans);
	}
	return 0;
}
/*
3
1 2 3
2 1 3
1 1 2
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值