从20 * 20的网格的左上角通往右下角有多少条路?

从一个×网格的左上角开始,有6条(不允许往回走)通往右下角的路。

 

对于20 ×20的网格,这样的路有多少条?

public class Test {
	public static int[][] arr = new int[20][20];
	public static void main(String[] args) {
		//初始化数数组
		for(int i = 0 ;i < 20 ;i ++){
			for(int j = 0 ; j < 20 ;j ++){
				if(i == 0 || j == 0) arr[i][j] = 1;
			}
		}
		arr[0][0] = 0;
		//填充数组
		for(int i = 1 ;i < 20 ;i ++){
			for(int j = 1 ; j < 20 ;j ++){
				arr[i][j] = arr[i][j-1] + arr[i-1][j];
			}
		}
		System.out.println("有" + arr[19][19] + "条路");
	}
}


L3-3 森森美图 分数 30 作者 戴龙翱、朱建科 单位 浙江大学 森森最近想让自己的朋友圈熠熠生辉,所以他决定自己写个美化照片的软件,并起名为森森美图。众所周知,在合照中美化自己的面部而不美化合照者的面部是让自己占据朋友圈高点的绝好方法,因此森森美图里当然得有这个功能。 这个功能的第一步是将自己的面部选中。森森首先计算出了一个图像中所有像素点与周围点的相似程度的分数,分数越低表示某个像素点越“像”一个轮廓边缘上的点。 森森认为,任意连续像素点的得分之和越低,表示它们组成的曲线和轮廓边缘的重合程度越高。为了选择出一个完整的面部,森森决定让用户选择面部上的两个像素点A和B,则连接这两个点的直线就将图像分为两部分,然后在这两部分中分别寻找一从A到B且与轮廓重合程度最高的曲线,就可以拼出用户的面部了。 然而森森计算出来得分矩阵后,突然发现自己不知道怎么找到这两曲线了,你能帮森森当上朋友圈的小王子吗? 为了解题方便,我们做出以下补充说明: 图像的左上角是坐标原点(0,0),我们假设所有像素按矩阵格式排列,其坐标均为非负整数(即横轴向右为正,纵轴向下为正)。 忽略正好位于连接A和B的直线(注意不是线段)上的像素点,即不认为这部分像素点在任何一个划分部分上,因此曲线也不能经过这部分像素点。 曲线是八连通的(即任一像素点可与其周围的8个像素连通),但为了计算准确,某像素连接对角相邻的斜向像素时,得分额外增加两个像素分数和的 2 ​ 倍减一。例如样例中,经过坐标为(3,1)和(4,2)的两个像素点的曲线,其得分应该是这两个像素点的分数和(2+2),再加上额外的(2+2)乘以( 2 ​ −1),即约为5.66。 输入格式: 输入在第一行给出两个正整数N和M(5≤N,M≤100),表示像素得分矩阵的行数和列数。 接下来N行,每行M个不大于1000的非负整数,即为像素点的分值。 最后一行给出用户选择的起始和结束像素点的坐标(X start ​ ,Y start ​ )和(X end ​ ,Y end ​ )。4个整数用空格分隔。 输出格式: 在一行中输出划分图片后找到的轮廓曲线的得分和,保留小数点后两位。注意起点和终点的得分不要重复计算。 输入样例: 6 6 9 0 1 9 9 9 9 9 1 2 2 9 9 9 2 0 2 9 9 9 1 1 2 9 9 9 3 3 1 1 9 9 9 9 9 9 2 1 5 4 输出样例: 27.04
07-02
这个问题可以建模为一个 **八连通网格图上的最短路径问题**,但有以下关键点需要注意: --- ## ✅ 问题核心理解 - 图像是一个 N × M 的网格,每个格子有一个得分值。 - 给定两个点 A(x₁, y₁) 和 B(x₂, y₂),我们要在图像中划分出两部分(忽略直线 AB 上的点)。 - 在每一边区域内找出一从 A 到 B 的曲线,使得其路径上像素分值总和最小(加上斜向移动时的额外分数)。 --- ## ✅ 关键规则总结 1. **八连通移动:** - 可以向上、下、左、右、四个对角方向移动。 2. **不同移动方式的代价:** - 横纵移动(上下左右):路径得分 = 目标点得分 - 斜向移动(对角线):路径得分 = 当前点得分 + 目标点得分 + (√2 - 1) × (当前点得分 + 目标点得分) 3. **不能经过连接 A 和 B 的直线上(不是线段)的点。** --- ## ✅ 解题思 ### 1. 建立坐标系与区域划分 - 将图像看作二维平面网格,原点在左上角。 - 计算连接 A 和 B 的直线方程:Ax + By + C = 0。 - 对于任意一点 (x, y),判断它是否在直线“上方”或“下方”,从而确定属于哪一侧区域。 > 注意:直线上的点要完全忽略! ### 2. Dijkstra 最短路径算法 - 构造一个加权图,每个节点是网格中的点。 - 使用优先队列进行 Dijkstra 算法寻找从 A 到 B 的最小路径得分。 - 移动时要考虑方向带来的额外得分。 - 起点得分只计算一次。 --- ## ✅ Python 实现代码如下: ```python import sys import math import heapq def input(): return sys.stdin.readline() # 判断点 (x, y) 是否在直线 AB 的某一侧 def side(A, B, x, y): ax, ay = A bx, by = B val = (bx - ax)*(y - ay) - (by - ay)*(x - ax) if val == 0: return 0 # 在直线上 return 1 if val > 0 else -1 # 分别表示两侧 # 八个方向:上下左右 + 四个对角 dirs = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)] def main(): import sys sys.setrecursionlimit(1000000) input = sys.stdin.read data = input().split() idx = 0 N = int(data[idx]); idx += 1 M = int(data[idx]); idx += 1 grid = [] for i in range(N): row = list(map(int, data[idx:idx+M])) grid.append(row) idx += M xs = int(data[idx]); idx += 1 ys = int(data[idx]); idx += 1 xe = int(data[idx]); idx += 1 ye = int(data[idx]); idx += 1 A = (xs, ys) B = (xe, ye) # 划分区域 s = side(A, B, *A) # A所在区域 assert s != 0 visited = [[False]*M for _ in range(N)] dist = [[float('inf')]*M for _ in range(N)] heap = [] heapq.heappush(heap, (grid[xs][ys], xs, ys)) # 起点得分计入一次 dist[xs][ys] = grid[xs][ys] while heap: cost, x, y = heapq.heappop(heap) if visited[x][y]: continue visited[x][y] = True if (x, y) == B: break for dx, dy in dirs: nx, ny = x + dx, y + dy if 0 <= nx < N and 0 <= ny < M and not visited[nx][ny]: if side(A, B, nx, ny) == s or (nx, ny) == B or (x, y) == B: # 如果该点在同侧 或者 是终点 或者 当前是终点,则可以访问 if (dx != 0 and dy != 0): # 对角线移动 extra = (math.sqrt(2) - 1) * (grid[x][y] + grid[nx][ny]) new_cost = cost + grid[nx][ny] + extra else: # 横纵移动 new_cost = cost + grid[nx][ny] if new_cost < dist[nx][ny]: dist[nx][ny] = new_cost heapq.heappush(heap, (new_cost, nx, ny)) print(f"{dist[xe][ye]:.2f}") if __name__ == "__main__": main() ``` --- ## ✅ 示例解析 输入样例: ``` 6 6 9 0 1 9 9 9 9 9 1 2 2 9 9 9 2 0 2 9 9 9 1 1 2 9 9 9 3 3 1 1 9 9 9 9 9 9 2 1 5 4 ``` 起点 A = (2,1),终点 B = (5,4) 程序将从 A 出发,在不穿过直线 AB 上的点的前提下,找到通往 B 的最小路径得分,并输出: ``` 27.04 ``` --- ## ✅ 复杂度分析 - 时间复杂度:O(N×M×log(N×M)),Dijkstra 算法使用堆优化。 - 空间复杂度:O(N×M) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值