1. 程式人生 > >【題解】codeforces293B[AHSOFNU codeforces訓練賽2 by hzwer]D.Distinct Paths dfs+剪枝+位運算

【題解】codeforces293B[AHSOFNU codeforces訓練賽2 by hzwer]D.Distinct Paths dfs+剪枝+位運算

題目連結

Description

You have a rectangular n × m-cell board. Some cells are already painted some of k colors. You need to paint each uncolored cell one of the k colors so that any path from the upper left square to the lower right one doesn’t contain any two cells of the same color. The path can go only along side-adjacent cells and can only go down or right.

Print the number of possible paintings modulo 1000000007 (109 + 7).

Input

The first line contains three integers n, m, k (1 ≤ n, m ≤ 1000, 1 ≤ k ≤ 10). The next n lines contain m integers each — the board. The first of them contains m uppermost cells of the board from the left to the right and the second one contains m cells from the second uppermost row and so on. If a number in a line equals 0, then the corresponding cell isn’t painted. Otherwise, this number represents the initial color of the board cell — an integer from 1 to k.

Consider all colors numbered from 1 to k in some manner.

Output

Print the number of possible paintings modulo 1000000007 (109 + 7).

Examples

Input

2 2 4 0 0 0 0

Output

48

Input

2 2 4 1 2 2 1

Output

0

Input

5 6 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Output

3628800

Input

2 6 10 1 2 3 4 5 6 0 0 0 0 0 0

Output

4096

大佬題解寫的非常好,摘抄如下:

題目大意: 給出一個n*m的矩陣,其中一些格子填了數,一些格子沒有。現要求將未填數的格子填上數字,使得矩陣從左上到右下(不允許向左或上走)的任意一條路徑上沒有兩個格子數字相同,數字範圍為1~K。 1<=n,m<=1000,1<=k<=10 分析: 首先一看,在(n+m-1)大於K時必定無解,這樣就把n,m範圍縮小到了10以內。 我們考慮搜尋解決。但是純暴搜時間不夠,可以用兩個剪枝優化: (1)可行性剪枝,如果在當前格子填數時,剩下的顏色已經不夠用則直接回溯。 (2)對稱性剪枝:例如我們當前填到了某個格子,我們記錄一下整個矩陣已使用的顏色,例如3,5都還沒用,那麼這個格子填上3或5,兩者最終算出的方案數是相同的,這樣我們就可以只計算3的方案數,5的直接加上3的就可以了。

#include<cstdio>
typedef long long ll;
const int mod=1e9+7;
int n,m,k,vis[11],a[11][11],f[11][11];//f[x][y]記錄每個階段顏色的使用情況 
ll ans;
void dfs(int x,int y)
{
	if(x==n+1)
	{
		if(++ans==mod)ans=0;
		return;
	}
	f[x][y]=f[x-1][y]|f[x][y-1];
	int cnt=0,p=1,q=k;ll sum=-1,pre;
	for(int i=1;i<=k;i++)if((f[x][y]&(1<<(i-1)))!=0)cnt++;//已用顏色數
	if(n-x+m-y+1>k-cnt)return;//可行性剪枝 
	if(a[x][y]>0)p=q=a[x][y];
	for(int i=p;i<=q;i++)
	    if((f[x][y]&(1<<(i-1)))==0)//當前狀態沒用過這種顏色 
	    {
	    	if(!vis[i])//這個顏色沒出現過 
	    	{
	    		if(sum>=0)//對稱性剪枝,如果sum>=0說明該位的顏色是沒出現過的,且已經考慮過 
	    		{
	    			ans+=sum;
	    			if(ans>=mod)ans-=mod;
	    			continue;
				}
				pre=ans;
			}
			f[x][y]^=(1<<(i-1)),vis[i]++;
			if(y==m)dfs(x+1,1);else dfs(x,y+1);
			f[x][y]^=(1<<(i-1)),vis[i]--;
			if(!vis[i])sum=(ans-pre)%mod;//對於沒用過的顏色,得到的sum是相等的 
		}
}
int main()
{
	//freopen("in.txt","r",stdin);;
    scanf("%d%d%d",&n,&m,&k);
    if(n+m-1>k)
    {
    	puts("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]>0)vis[a[i][j]]++;//記錄顏色出現數 
		}
	dfs(1,1);
	printf("%lld\n",ans);
	return 0;
}

總結

果然爆搜才是男人的浪漫。