SP13980 SUDOGOB - Sudoku goblin题解
一道显然的
建模#
首先考虑一个数独,需要满足的条件。
-
每一行都需要不同。
-
每一列都需要不同。
-
每一个宫格都需要不同。
-
八十一个格子都不能为
。
注意最后一个情况,这是最容易遗漏的一个情况。
根据
考虑每一种情况#
我们让
- 当
为 时。
那么这个位置九个数都有可能被填,那么就都需要加上去。
- 当
不为 时。
那么这个位置就只有唯一的解法。
考虑每一种限制#
对于之前的情况,我们需要在不同的列中,根据限制加点。
由于有四个限制,我们可以加四个点。
代码大致如下:
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 0 + (i - 1) * 9 + j);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 1 + (i - 1) * 9 + k);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 2 + (j - 1) * 9 + k);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 3 + ((i - 1) / 3 * 3 + (j - 1) / 3) * 9 + k);
其余的就可以直接写板子了。
Code#
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5000;
int n , m , t , sum , cnt , tot , a[15][15];
int l[maxn] , r[maxn] , u[maxn] , d[maxn] , h[maxn] , qx[maxn] , qy[maxn] , vy[maxn] , ans[maxn];
inline int read()
{
int s = 0 , f = 1; char ch;
while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
while(isdigit(ch)) s = s * 10 + ch - '0' , ch = getchar();
return s * f;
}
inline void init()
{
memset(l , 0 , sizeof(l));
memset(r , 0 , sizeof(r));
memset(d , 0 , sizeof(d));
memset(u , 0 , sizeof(u));
memset(h , -1 , sizeof(h));
for(int i = 0;i <= m;i++)
{
l[i] = i - 1 , r[i] = i + 1;
d[i] = u[i] = i;
}
tot = 0 , cnt = m + 1 , l[0] = m , r[m] = 0;
memset(vy , 0 , sizeof(vy));
memset(qx , 0 , sizeof(qx));
memset(qy , 0 , sizeof(qy));
memset(ans , 0 , sizeof(ans));
}
inline void add(int x , int y)
{
qx[cnt] = x , qy[cnt] = y , vy[y]++;
u[cnt] = y , d[cnt] = d[y] , u[d[y]] = cnt , d[y] = cnt;
if(h[x] < 0) h[x] = l[cnt] = r[cnt] = cnt;
else r[cnt] = h[x] , l[cnt] = l[h[x]] , l[h[x]] = r[l[h[x]]] = cnt;
cnt++;
}
inline void remove(int p)
{
l[r[p]] = l[p] , r[l[p]] = r[p];
for(int i = d[p];i != p;i = d[i])
for(int j = r[i];j != i;j = r[j])
{
vy[qy[j]]--;
u[d[j]] = u[j] , d[u[j]] = d[j];
}
return;
}
inline void resume(int p)
{
for(int i = u[p];i != p;i = u[i])
for(int j = l[i];j != i;j = l[j])
{
vy[qy[j]]++;
u[d[j]] = d[u[j]] = j;
}
l[r[p]] = r[l[p]] = p;
return;
}
inline void dfs()
{
if(!r[0])
{
sum++;
for(int i = 1;i <= tot;i++)
a[(ans[i] - 1) / 81 + 1][(ans[i] - 1) / 9 % 9 + 1] = (ans[i] - 1) % 9 + 1;
}
int p = r[0];
for(int i = r[0];i;i = r[i])
if(vy[p] > vy[i]) p = i;
remove(p);
for(int i = d[p];i != p;i = d[i])
{
ans[++tot] = qx[i];
for(int j = r[i];j != i;j = r[j]) remove(qy[j]);
dfs();
for(int j = l[i];j != i;j = l[j]) resume(qy[j]);
tot--;
}
resume(p);
}
int main()
{
// freopen("1.in" , "r" , stdin);
t = read() , n = 729 , m = 324;
while(t--)
{
sum = 0 , init();
for(int i = 1;i <= 9;i++)
{
for(int j = 1;j <= 9;j++)
{
a[i][j] = read();
for(int k = 1;k <= 9;k++)
{
if(!a[i][j] || a[i][j] == k)
{
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 0 + (i - 1) * 9 + j);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 1 + (i - 1) * 9 + k);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 2 + (j - 1) * 9 + k);
add(((i - 1) * 9 + j - 1) * 9 + k , 81 * 3 + ((i - 1) / 3 * 3 + (j - 1) / 3) * 9 + k);
}
}
}
}
dfs();
cout << sum << endl;
if(sum == 1)
{
for(int i = 1;i <= 9;i++)
{
for(int j = 1;j <= 9;j++)
cout << a[i][j] << " ";
cout << endl;
}
}
}
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/15838949.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)