[luogu U137467] flying chess (dfs) (search pruning)

Flight chess

Title Link: luogu U137467

General idea of the topic

Give you an n*m grid, and then there are some numbers with 1~k on it.
Then you have to fill the grid with a number of 1~k, and ask how many filling schemes you have. No path from top left to bottom right passes through the same number.
Then define that these paths can only go to the right or down.

thinking

You first consider to see which points can't have the same color.

Look, you can get a pink dot ( i , j ) (i,j) (i,j) cannot be the same color as the red dot.
Specifically ( 1 , 1 ) (1,1) (1,1) to ( i , j ) (i,j) Prefix matrix of (i,j), ( i , j ) (i,j) (i,j) to ( n , m ) (n,m) Suffix matrix of (n,m).

Then we thought about it, there is no way, consider using metaphysical algorithm - Search and pruning!!!
Then we can fill in from top to bottom and from left to right. After you fill in each time, you can maintain whether each color prefix matrix appears.

Then, because you didn't fill in the points in the suffix matrix and only have their own numbers, you can run the suffix matrix with their own numbers in advance, and then make a simple judgment.

Then this is the ordinary dfs. Next, consider pruning.

First give a small pruning, that is, if the color that can be selected at the current point is less than the color it needs to reach the end, there is no solution.
(the colors that can be selected here cannot be seen from the suffix matrix, because the numbers in your suffix matrix may be used later, so you can only see the filled prefix matrix)

Then give a big prune. That is, if a number you currently select appears for the first time in this matrix, the contribution of these selected numbers is the same. Then we only need to calculate it once and record this value. (don't be global, each location is different)
Then, if you find these points when enumerating, you don't need to dfs go on.

Then you can pass!

code

#include<cstdio>
#define ll long long
#define mo 1000000007

using namespace std;

int n, m, k, a[15][15], sum[15][15][15];
int hounum[15][15][15], num[15];
ll ans;

void clac(int x, int y) {//Calculate the number of occurrences of each color in the previous matrix
	for (int i = 1; i <= k; i++)
		sum[x][y][i] = sum[x - 1][y][i] + sum[x][y - 1][i] - sum[x - 1][y - 1][i];
}

ll work(int x, int y) {
	if (y > m) {
		y = 1; x++;
	}
	if (x > n) {
		return 1;
	}
	if (a[x][y]) {
		clac(x, y);
		if (sum[x][y][a[x][y]] || hounum[x][y][a[x][y]] > 1) return 0;
		sum[x][y][a[x][y]]++;
		ll re = work(x, y + 1);
		sum[x][y][a[x][y]]--;
		return re;
	}
	
	ll rem = -1, re = 0;
	clac(x, y);
	int ok = k;
	for (int i = 1; i <= k; i++)
		if (sum[x][y][i]) ok--;
	if (n + m - x - y > ok) return 0;//The number of colors you can walk with the front calculation is not enough to reach the end
	for (int i = 1; i <= k; i++) {
		if (sum[x][y][i] || hounum[x][y][i]) continue ;
		sum[x][y][i]++;
		num[i]++;
		if (num[i] == 1) {//The number contribution of the first occurrence is the same, which can be calculated at one time, and used later
			if (rem == -1) rem = work(x, y + 1);
			re = (re + rem) % mo;
		}
		else re = (re + work(x, y + 1)) % mo;
		num[i]--;
		sum[x][y][i]--;
	}
	return re;
}

int main() {
	scanf("%d %d %d", &n, &m, &k);
	
	if (n + m - 1 > k) {
		printf("0"); return 0;
	}
	
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			scanf("%d", &a[i][j]);
			if (a[i][j]) num[a[i][j]]++, hounum[i][j][a[i][j]] = 1;
		}
	
	for (int i = n; i >= 1; i--)//Calculate the occurrence times of each color in the following matrix (because the latter ones are not filled in, we only need to look at the number they have)
		for (int j = m; j >= 1; j--) {
			for (int kk = 1; kk <= k; kk++)
				hounum[i][j][kk] += hounum[i + 1][j][kk] + hounum[i][j + 1][kk] - hounum[i + 1][j + 1][kk];
		}
	
	ans = work(1, 1);
	printf("%lld", ans);
	
	return 0;
} 

Tags: dfs

Posted on Wed, 29 Sep 2021 15:19:37 -0400 by scooter41