这个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;
}
博客介绍了如何解决竞赛编程题目CF293B「Distinct Paths」。作者指出初始的n, m限制是误导性的,实际问题规模远小于1000。当n + m - 1 > k时,问题无解。为了解决这个问题,提出了采用深度优先搜索(DFS)的方法,并进行了剪枝优化:包括可行性剪枝(若剩余步数大于可用颜色则剪枝)和对称性剪枝(首次填充颜色的对称变换不影响结果)。优化后的DFS策略显著减少了搜索量,使得即使在棋盘稀疏的情况下也能快速求解。"
88186145,8092602,CSS样式处理:文字溢出与背景图片技巧,"['前端开发', 'CSS', 'HTML', '布局', '背景图片']
323

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



