Kakuro
Posted harryhqg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kakuro相关的知识,希望对你有一定的参考价值。
这是个搜索题,不过有人非(xian)常(zhe)牛(wu)逼(liao)用网络流过了此题
数据范围提示性很强,感觉暴搜?
显然9^n要你的老命。。。
是否能够高斯消元? 好像比较难满足每个 \(run\) 数字不同的要求QWQ
思考怎么优化搜索?
第一是优化搜索顺序
试了试枚举行和枚举列都 \(TLE72\)
绝望.jpg
第二个考虑就是剪枝
剪枝就比较难考虑了
思考之后有了一些想法:
1.不能有数字上的重复
2.列和行的和的信息要可行
3.一些稀奇古怪的想法QWQ
首先第一条剪枝方法非常重要
可以想到状压dp预处理一些东西
\(dp[len][sum][used]\) 表示长度为 \(len\),和为 \(sum\) 的方案中用过used集合的数是否可行
这样的预处理非常精妙,我们可以通过它少去很多不必要的转移
在dfs时,我们定义f[x][y][0/1] 表示这个点,行/列能够填的数的集合
还有一些细节需要注意,没写很容易TLE
QwQ我太菜了,贴代码滚回去写wll了
// By Hacheylight
#include <map>
#include <set>
#include <ctime>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <numeric>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std ;
//#define int long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define loop(it, v) for (auto it = v.begin(); it != v.end(); it++)
#define cont(i, x) for (int i = head[x]; i; i = e[i].nxt)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define all(x) x.begin(), x.end()
#define SC(t, x) static_cast <t> (x)
#define ub upper_bound
#define lb lower_bound
#define pqueue priority_queue
#define mp make_pair
#define pb push_back
#define pof pop_front
#define pob pop_back
#define fi first
#define se second
#define y1 y1_
#define Pi acos(-1.0)
#define iv inline void
#define enter cout << endl
#define siz(x) ((int)x.size())
#define file(x) freopen(x".in", "r", stdin),freopen(x".out", "w", stdout)
typedef long double ld ;
typedef long long ll ;
typedef unsigned long long ull ;
typedef pair <int, int> pii ;
typedef pair <ll, int> pli ;
typedef vector <int> vi ;
typedef vector <pii> vii ;
typedef vector <vi> vvi ;
typedef queue <int> qi ;
typedef queue <pii> qii ;
typedef set <int> si ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
const int N = 35 ;
const int INF = 0x3f3f3f3f ;
const int iinf = 1 << 30 ;
const ll linf = 2e18 ;
const int mod = 1000000007 ;
const double eps = 1e-7 ;
void douout(double x) printf("%lf\n", x + 0.0000000001) ;
template <class T> void print(T a) cout << a << endl ; exit(0) ;
template <class T> void chmin(T &a, T b) if (a > b) a = b ;
template <class T> void chmax(T &a, T b) if (a < b) a = b ;
void add(int &a, int b) a = a + b < mod ? a + b : a + b - mod ;
void sub(int &a, int b) a = (a - b + mod) % mod ;
void mul(int &a, int b) a = (ll) a * b % mod ;
int addv(int a, int b) return (a += b) >= mod ? a -= mod : a ;
int subv(int a, int b) return (a -= b) < 0 ? a += mod : a ;
int mulv(int a, int b) return (ll) a * b % mod ;
int read()
int f = 1, x = 0 ;
char ch = getchar() ;
while (!isdigit(ch)) if (ch == '-') f = -1 ; ch = getchar() ;
while (isdigit(ch)) x = x * 10 + ch -'0' ; ch = getchar() ;
return x * f ;
int pw(int a, int b)
int s = 1 ;
for (; b; b >>= 1, a = (ll) a * a % mod)
if (b & 1) s = (ll) s * a % mod ;
return s ;
int dp[N + 5][(1 << 9)][10] ;
// dp[sum][used][len]
// f[i][j][0/1] 表示搜索时,[i,j] 可用的数字集合
#define bitcnt(x) __builtin_popcount(x)
void prework() // work out dp[][][]
rep(i, 0, (1 << 9) - 1) dp[0][i][0] = 1 ;
rep(i, 0, 35)
for (int num = 1; num <= 5; num++)
for (int k = 0; k < (1 << 9); k++)
if (bitcnt(k) < num) continue ;
for (int j = 0; j < 9; j++)
if (k & (1 << j))
if (i - (j + 1) >= 0 && dp[i - (j + 1)][k ^ (1 << j)][num - 1])
dp[i][k][num] = 1 ;
break ;
int n, m ;
int f[10][10][2] ;
int blo[10][10], sum[10][10][2] ;
int cnt[10][10][2], ans[10][10] ;
int last[(1 << 9) + 10] ;
vii v ; // 将空的位置排序存进去方便搜索
bool dfs(int num) // main progess
if (num == siz(v)) return 1 ;
int i = v[num].fi, j = v[num].se ;
if (!blo[i][j]) return dfs(num + 1) ;
int s = f[i][j][0] & f[i][j][1] ;
if (!dp[sum[i][j][0]][f[i][j][0]][cnt[i][j][0]]) return 0 ;
if (!dp[sum[i][j][1]][f[i][j][1]][cnt[i][j][1]]) return 0 ;
if (cnt[i][j][0] == 1)
int tmp = sum[i][j][0] ;
if (tmp <= 9 && (s & (1 << (tmp - 1))) && tmp > 0)
int num0 = sum[i][j][0] - tmp ;
int num1 = sum[i][j][1] - tmp ;
if (num0 < 0 || num1 < 0) return 0 ;
if (!blo[i + 1][j] && num0 != 0) return 0 ;
if (!blo[i][j + 1] && num1 != 0) return 0 ;
sum[i + 1][j][0] = num0 ;
sum[i][j + 1][1] = num1 ;
f[i + 1][j][0] = f[i][j][0] ^ (1 << (tmp - 1)) ;
f[i][j + 1][1] = f[i][j][1] ^ (1 << (tmp - 1)) ;
ans[i][j] = tmp ;
if (dfs(num + 1)) return 1 ;
return 0 ;
if (cnt[i][j][1] == 1)
int tmp = sum[i][j][1] ;
if (tmp <= 9 && (s & (1 << (tmp - 1))) && tmp > 0)
int num0 = sum[i][j][0] - tmp ;
int num1 = sum[i][j][1] - tmp ;
if (num0 < 0 || num1 < 0) return 0 ;
if (!blo[i + 1][j] && num0 != 0) return 0 ;
if (!blo[i][j + 1] && num1 != 0) return 0 ;
sum[i + 1][j][0] = num0 ;
sum[i][j + 1][1] = num1 ;
f[i + 1][j][0] = f[i][j][0] ^ (1 << (tmp - 1)) ;
f[i][j + 1][1] = f[i][j][1] ^ (1 << (tmp - 1)) ;
ans[i][j] = tmp ;
if (dfs(num + 1)) return 1 ;
return 0 ;
while (s)
int tmp = last[s] ;
s ^= (1 << tmp) ;
int tot0 = f[i][j][0] ^ (1 << tmp) ;
int tot1 = f[i][j][1] ^ (1 << tmp) ;
int num0 = sum[i][j][0] - (tmp + 1) ;
int num1 = sum[i][j][1] - (tmp + 1) ;
if (num0 < 0 || num1 < 0) return 0 ;
if (!dp[num0][tot0][cnt[i + 1][j][0]]) continue ;
if (!dp[num1][tot1][cnt[i][j + 1][1]]) continue ;
sum[i + 1][j][0] = num0 ;
sum[i][j + 1][1] = num1 ;
f[i + 1][j][0] = tot0 ;
f[i][j + 1][1] = tot1 ;
ans[i][j] = tmp + 1 ;
if (dfs(num + 1)) return 1 ;
return 0 ;
signed main()
freopen("input.txt", "r", stdin) ;
freopen("output.txt", "w", stdout) ;
prework() ;
rep(i, 0, (1 << 9) - 1) last[i] = (int) log2(lowbit(i)) ;
// rep(i, 1, 10) last[(1 << (i - 1))] = i ;
scanf("%d%d", &n, &m) ;
rep(i, 0, n - 1)
rep(j, 0, m - 1)
f[i][j][0] = f[i][j][1] = (1 << 9) - 1 ;
string s ; cin >> s ;
if (s == ".....") blo[i][j] = 1 ;
else
if (s[0] != 'X') sum[i + 1][j][0] = (s[0] - '0') * 10 + s[1] - '0';
if (s[3] != 'X') sum[i][j + 1][1] = (s[3] - '0') * 10 + s[4] - '0';
rep(i, 0, n + m - 1)
rep(j, 0, n + m - 1)
int x = i - j, y = j ;
if (x < 0) break ;
if (x >= 0 && x < n && y >= 0 && y < m && blo[x][y]) v.pb(mp(x, y)) ;
per(i, n - 1, 0)
per(j, m - 1, 0)
if (!blo[i][j]) continue ;
cnt[i][j][0] = cnt[i][j][1] = 1 ;
if (blo[i + 1][j]) cnt[i][j][0] += cnt[i + 1][j][0] ;
if (blo[i][j + 1]) cnt[i][j][1] += cnt[i][j + 1][1] ;
dfs(0) ;
rep(i, 0, n - 1)
rep(j, 0, m - 1)
if (blo[i][j])
printf("%d ", ans[i][j]) ;
else
printf("_ ") ;
enter ;
return 0 ;
以上是关于Kakuro的主要内容,如果未能解决你的问题,请参考以下文章