池塘

1 篇文章 0 订阅

Description

从前有两个青蛙王国,两个王国商业都非常繁荣。但是一块池塘阻碍了两国的商业往来。一次,两只青蛙在池塘的两岸,他们都希望到对岸去。我们可以将池塘看做一个 n × m n×m n×m 的矩形,在每个格子里,可能会有荷叶。青蛙必须踩在荷叶上,不能跳进水里。如图青蛙可以向他前方的5个有荷叶的地方跳去。
在这里插入图片描述
由于有的地方荷叶比较小,当一个青蛙从该荷叶上跳走之后,荷叶会沉入水底,两个青蛙也不能同时跳上这种荷叶。两个青蛙想知道有多少种方式使他们都到达对岸。第一个青蛙可以从第一行任何一个有荷叶的格子出发。第二个青蛙可以从最后一行任何一个有荷叶的格子出发。当第一个青蛙到达最后一行任何一个有荷叶的格子时,他就算到达了对岸。当第二个青蛙到达第一行任何一个有荷叶的格子时,他也算到达了对岸。请你帮助青蛙们计算有多少种方案可以让他们都到达对岸。
注:第一个青蛙只能向下跳,第二个青蛙只能向上跳。青蛙并不能跳出矩形区域。

Input

输入的第一行包含两个整数 n n n m m m
第2至 n + 1 n+1 n+1 行包含 m m m 个整数。若该数为0,表示该格子上没有荷叶,青蛙不能通过。若该数为1,表示该格子上的荷叶只允许一个青蛙通过。若该数为2,表示该格子上的荷叶可以允许两个青蛙都通过。

Output

输出的第一行包含一个整数,表示两个青蛙都到达对岸的方案数。由于结果可能非常大,输出答案模1000000007的结果。

Sample Input

Test Case #1

4 1
2
0
0
2

Test Case #2

5 3
1 0 1
0 0 0
0 1 0
0 0 0
1 0 1

Test Case #3

4 3
1 1 0
0 0 0
0 0 1
2 0 0

Sample Output

Test Case #1

1

Test Case #2

0

Test Case #3

2

Data

对于30%的数据: n , m ≤ 10 n , m \leq 10 n,m10
对于另外20%的数据,格子只有0或2两种
对于100%的数据, n , m ≤ 50 n , m \leq 50 n,m50

Associate

看样子这道题暴力的分数并不是很多。不如想想正解
但是非常抱歉,我考试的时候只剩下15min了。真是失误,我获得了0分的好成绩。因为根本就没怎么想,没时间了,样例都没测就交了

Solution

直接来说正解怎么做吧:
很简单能发现,这道题应该是一个动态规划题。我们考虑设计一个状态:
d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l] 表示当第一支青蛙走到 ( i , j ) (i , j) (i,j) ,第二支青蛙走到 ( k , l ) (k , l) (k,l) 的时候的状态数目。

这里有一个常用的技巧:因为图是可以颠倒的,但是一个从上面走,一个从下面走,不方便计数,那么可以把图翻个180度,相当于两只青蛙都从一边出发,方案数必定是一样的

考虑这个dp方程。实际上还是挺好想的。但是其中可以添加一个剪枝,就是 k k k 一定要在 i − 3 i - 3 i3 i + 3 i + 3 i+3 之间。因为这样的话,他们差的不会很远,否则可能会导致一只青蛙没地方走了的情况,只能原地不动。这是不能允许的。

剩下的就非常简单了。我们循环一下5种转移方式(就是青蛙的跳动方式),分别更新。
这里要注意,只更新当前行数更小的那只青蛙,让他往前面跳,永远都是慢的在追快的,否则会越差越多,最后超出了3的范围,就不能更新了。
在方程中不断累加,最后把都在最后一行的两只青蛙的方案数加起来就行了。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>

using namespace std;

inline int read() {
    int x = 0 , f = 1; char ch = getchar();
    for ( ; !isdigit(ch) ; ch = getchar()) if (ch == '-') f = -1;
    for ( ; isdigit(ch) ; ch = getchar()) x = x * 10 + ch - '0';
    return x * f;
}

const int maxn = 51;
const int mod = 1e9 + 7;

const int maxDir = 5;
const int dirx[maxDir] = {1 , 1 , 2 , 2 , 3}; 
const int diry[maxDir] = {-2 , 2 , -1 , 1 , 0};

int n , m;

int _map[maxn][maxn];

int dp[maxn][maxn][maxn][maxn];

int ans;

int main() {
	n = read() , m = read();
	for (int i = 1 ; i <= n ; i ++) {
		for (int j = 1 ; j <= m ; j ++) {
			_map[i][j] = read();
		}
	}
	
	for (int i = 1 ; i <= m ; i ++) {
		for (int j = 1 ; j <= m ; j ++) {
			if (i == j && _map[1][i] == 2) {//两只青蛙一起站在一个为2的荷叶上
				dp[1][i][1][i] = 1;
			}
			else if (i != j && _map[1][i] && _map[1][j]) {//两只青蛙分别站在不是水的两片荷叶上
				dp[1][i][1][j] = 1;
			}
		}
	}
	
	for (int i = 1 ; i <= n ; i ++) {
		for (int j = 1 ; j <= m ; j ++) {
			for (int k = max(1 , i - 3) ; k <= min(n , i + 3) ; k ++) {
				for (int l = 1 ; l <= m ; l ++) {
					if (dp[i][j][k][l]) {
						
						if (i >= k) {
							for (int dir = 0 ; dir < maxDir ; dir ++) {
								int newx = k + dirx[dir] , newy = l + diry[dir];
								
								if (newx <= 0 || newx > n || newy <= 0 || newy > m) { //越界
									continue;
								}
								
								if (!_map[newx][newy]) { //下面要去的点是水
									continue;
								}
								
								if (newx == i && newy == j && _map[i][j] == 1) {//两只青蛙一起到了一个只能装1个青蛙的荷叶上
									continue;
								}
								
								dp[i][j][newx][newy] = (dp[i][j][newx][newy] + dp[i][j][k][l]) % mod;//累加
							}
						}
						else {//同理
							for (int dir = 0 ; dir < maxDir ; dir ++) {
								int newx = i + dirx[dir] , newy = j + diry[dir];
								
								if (newx <= 0 || newx > n || newy <= 0 || newy > m) {
									continue;
								}
								
								if (!_map[newx][newy]) {
									continue;
								}
								
								if (newx == k && newy == l && _map[k][l] == 1) {
									continue;
								}
								
								dp[newx][newy][k][l] = (dp[newx][newy][k][l] + dp[i][j][k][l]) % mod;
							}
						}
					}
				}
			}
		}
	}
	
	for (int i = 1 ; i <= m ; i ++) {
		for (int j = 1 ; j <= m ; j ++) {
			ans = (ans + dp[n][i][n][j]) % mod; // 第一只青蛙在 i ,第二只青蛙在 j 的方案数
		}
	}
	
	printf("%d\n" , ans);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"池塘夜降彩色雨"这个描述可能是对一种艺术效果、诗歌意境或者是程序中的某种动画效果的比喻。在Java编程中,并没有直接的内置语法去创造出真实的“彩色雨”从夜晚的池塘降落的场景。然而,你可以通过图形处理库如Swing或JavaFX,结合随机数生成和颜色管理,模拟这种视觉效果。 例如,你可以创建一个循环,定时在一个二维数组(代表池塘)上随机地点落下不同颜色的元素(可以视为“雨滴”),并且在夜间背景(通常是黑色)的映衬下,形成色彩斑斓的效果。下面是一个简化的示例: ```java import java.awt.Color; import java.awt.Graphics2D; import javax.swing.JFrame; import javax.swing.JPanel; public class ColorRain extends JPanel { private static final int NIGHT_WIDTH = 800; private static final int NIGHT_HEIGHT = 600; private Color[] colors = {Color.RED, Color.BLUE, Color.YELLOW}; @Override protected void paintComponent(Graphics2D g) { super.paintComponent(g); for (int i = 0; i < 50; i++) { // 每次绘制50个雨滴 int x = (int)(Math.random() * NIGHT_WIDTH); int y = NIGHT_HEIGHT - 1; // 雨滴从顶部开始落下来 g.setColor(colors[(int)(Math.random() * colors.length)]); g.fillOval(x, y, 5, 5); // 画一个小圆点表示雨滴 y -= 5; // 雨滴下落 } } public static void main(String[] args) { JFrame frame = new JFrame("池塘夜降彩色雨"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(NIGHT_WIDTH, NIGHT_HEIGHT); frame.add(new ColorRain()); frame.setVisible(true); } } ``` 这只是一个基础示例,实际效果可能需要进一步优化和调整。运行这个程序,你会看到一个简单的彩色雨效果在池塘(窗口大小的面板)上动态显示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值