zoukankan      html  css  js  c++  java
  • Kakuro

    这是个搜索题

    数据范围提示性很强,感觉暴搜?

    显然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我太菜了,贴代码滚回去写 (dp)

    #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
    ", 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 ;
    }
    
  • 相关阅读:
    程序书写规范
    点灯主要顺序
    复用功能重映射
    STM32 (战舰)
    html5 javascript 新增加的高级选择器更精准更实用
    html5 javascript 事件练习3键盘控制练习
    html5 javascript 事件练习3随机键盘
    html5 javascript 事件练习2
    html5 javascript 事件练习1
    html5dom2
  • 原文地址:https://www.cnblogs.com/harryhqg/p/Kakuro.html
Copyright © 2011-2022 走看看