这个n,m≤1000n,m≤1000n,m≤1000明显是唬人的,我们经过研究后可以发现,当n+m−1>kn + m - 1>kn+m−1>k时就无解了。因此我们发现,n,m的实际范围是非常小的,因此考虑dfs。
但是单纯的dfs时间复杂度仍不足以通过此题,我们考虑优化:
1.可行性剪枝。若剩下步数大于可用颜色就剪掉
- 对称性剪枝。如果当前是第一次填颜色x,那么把x换成其他第一次填的颜色结果不变
这样就使的搜索量大大减少,即使棋盘相当稀疏也能瞬间出解
Code
#include <cstdio>
#include <cstring>
#define lowbit(x) ((x) & (-(x)))
#define Int register int
using namespace std;
const int MOD = 1000000007;
int rc[1007][1007] , n , m , k , ans;
int rec[1007][1007] , used[1000007];
inline int dfs(Int x , Int y)
{
if (y > m) y = 1 , ++ x;
if (x == n + 1) return 1;
int now = rec[x - 1][y]|rec[x][y-1],tmp=-1;
int ret = 0 , tot = 0;
for (Int i = 1 ; i <= k ; ++ i) tot += !((1 << i - 1) & now);
if (n + m - x - y + 1 > tot) return 0;
for (Int i = 1 ; i <= k ; ++ i)
{
if ((1 << i - 1) & now) continue;
if (!rc[x][y] || rc[x][y] == i)
{
rec[x][y] = now | (1 << i - 1);
if (++ used[i] == 1)
{
if (tmp == -1) tmp = dfs(x , y + 1);
ret += tmp;
} else ret += dfs(x , y + 1);
ret %= MOD;
-- used[i];
}
}
return ret;
}
int main(void)
{
int cnt = 0;
scanf("%d%d%d" , &n , &m , &k);
if (n + m - 1 > k) {putchar('0'); return 0;}
for (Int i = 1 ; i <= n ; ++ i)
for (Int j = 1 ; j <= m ; ++ j)
{
scanf("%d",&rc[i][j]);
cnt += (!rc[i][j]);
++ used[rc[i][j]];
}
printf("%d\n" , dfs(1 , 1));
return 0;
}
638



被折叠的 条评论
为什么被折叠?



