码迷,mamicode.com
首页 > 其他好文 > 详细

Kakuro

时间:2019-07-17 00:46:09      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:efi   chm   代码   freopen   范围   main   集合   back   顺序   

这是个搜索题,不过有人非(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

标签:efi   chm   代码   freopen   范围   main   集合   back   顺序   

原文地址:https://www.cnblogs.com/harryhqg/p/11198136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!