Description
给出一个
n×m
的矩阵,有一些格子已经有颜色了,现在要给每个没染色的格子染色,颜色有
k
种,用
Input
第一行三个整数
Output
输出方案数,结果模 109+7
Sample Input
2 2 4
0 0
0 0
Sample Output
48
Solution
由于一条从左上角到右下角的路径有 n+m−1 个格子,为使每个格子颜色互不相同则需满足 n+m−1≤k ,否则都无解,故问题规模很小,直接暴搜求方案数即可,注意有两个重要剪枝
1.每次选颜色时,如果该颜色之前已经被用过则不用了,用
s[x][y]
表示从左上角到格子
(x,y)
已用的颜色状态(用
k
位
2.假设有几种颜色是第一次用,由于这些颜色其实只是编号不同,当前用谁之后的方案数都一样,故只求一次即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=1111;
#define mod 1000000007
int n,m,k,a[maxn][maxn],num[maxn],s[maxn][maxn],f[maxn];
void add(int &x,int y)
{
x=x+y>=mod?x+y-mod:x+y;
}
int dfs(int x,int y)
{
if(y==m+1)x++,y=1;
if(x==n+1)return 1;
int ans=0,S=s[x-1][y]|s[x][y-1];
int T=~S&((1<<k)-1);
if(n-x+m-y+1>f[T])return 0;
int res=-1;
for(int i=0;i<k;i++)
if(T&(1<<i))
if(a[x][y]==0||a[x][y]==i+1)
{
num[i+1]++;
s[x][y]=S|(1<<i);
if(num[i+1]==1)
{
if(res==-1)res=dfs(x,y+1);
add(ans,res);
}
else add(ans,dfs(x,y+1));
num[i+1]--;
}
return ans;
}
int main()
{
f[0]=0;
for(int i=1;i<1024;i++)f[i]=f[i/2]+(i&1);
scanf("%d%d%d",&n,&m,&k);
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]]++;
}
if(n+m-1>k)printf("0\n");
else printf("%d\n",dfs(1,1));
return 0;
}