kuangbin专题三:Dancing Links

前:上个专题有点麻烦,暂时不想写了。

 

Luogu P4929

思路:这题不是kuangbin专题里的,但是一道裸dancing links题,算法模板来自OI wiki。Dancing links在recover和remove时的遍历方向需要注意,虽然模板里的方向是相反的,但我测试发现方向可以变化,虽然有时会TLE。具体原因还没找到。

#include<iostream>
#include<cstring>
using namespace std;
int ans, stk[505];

struct DLX{
    static const int maxn = 500 * 500 + 5;
    int n, m, tot;
    int U[maxn], D[maxn], L[maxn], R[maxn];
    int first[maxn], col[maxn], row[maxn], siz[maxn];

    void build(int r, int c){
        n = r, m = c;
        for(int i = 0; i <= m; i++){
            U[i] = D[i] = i;
            L[i] = i - 1, R[i] = i + 1;
        }
        L[0] = c, R[c] = 0, tot = c;
        memset(first, 0, sizeof(first));
        memset(siz, 0, sizeof(siz));
    }

    void insert(int r, int c){
        tot++;
        row[tot] = r, col[tot] = c, siz[c]++;
        D[tot] = D[c], U[D[c]] = tot, U[tot] = c, D[c] = tot;
        if(!first[r])
            first[r] = L[tot] = R[tot] = tot;
        else{
            R[tot] = R[first[r]], L[R[first[r]]] = tot;
            L[tot] = first[r], R[first[r]] = tot;
        }
    }

    void remove(int c){
        L[R[c]] = L[c], R[L[c]] = R[c];
        for(int i = D[c]; i != c; i = D[i]){
            for(int j = R[i]; j != i; j = R[j])
                D[U[j]] = D[j], U[D[j]] = U[j], siz[col[j]]--;
        }
    }

    void recover(int c){
        L[R[c]] = R[L[c]] = c;
        for(int i = D[c]; i != c; i = D[i])
            for(int j = R[i]; j != i; j = R[j])
                D[U[j]] = U[D[j]] = j, siz[col[j]]++;
    }

    int dance(int dep){
        if(!R[0]){
            ans = dep;
            return 1;
        }
        int c = R[0];
        for(int i = R[0]; i != 0; i = R[i])
            if(siz[i] < siz[c])
                c = i;
        remove(c);
        for(int i = D[c]; i != c; i = D[i]){
            stk[dep] = row[i];
            for(int j = R[i]; j != i; j = R[j]) remove(col[j]);
            if(dance(dep + 1)) return 1;
            for(int j = L[i]; j != i; j = L[j]) recover(col[j]);
        }
        recover(c);
        return 0;
    }
}solver;

int main(){
    int r, c;
    cin >> r >> c;
    solver.build(r, c);
    for(int i = 1; i <= r; i++)
        for(int j = 1; j <= c; j++){
            int x;
            cin >> x;
            if(x)
                solver.insert(i, j);
        }
    solver.dance(1);
    if(ans)
        for(int i = 1; i < ans ; i++)
            cout << stk[i] << ' ';
    else
        cout << "No Solution!";
    cout << endl;
    return 0;
}
View Code

 

ZOJ3209 Treasure Map

思路:二维的Dancing Links问题,感觉搜索也可以做。我们需要确保任意两个piece互不覆盖,但普通DLX只能处理一维情况,所以我们要稍微变化一下。把n行m列的矩阵展开成n×m的一维数组,那么每个piece都能以一个n×m的一维数组表示,有piece的地方为1,没有为0。问题就转换成从p个piece里找到一个精确覆盖。

 

HDU2295 Radar

思路:行数为K,列数为N的精确覆盖。算出所有雷达到所有城市的距离,再二分查找这些距离,找到一个能够覆盖所有城市的方案且半径最小的方案。注意输出格式,卡了我好久(╬▔皿▔)╯,下面的代码是网上找的,稍微改一下,自己写的因为输出格式问题被删了,没保存下来。

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<algorithm>

#define DEBUG

using namespace std;

const int maxn = 55;
const int maxm = 55;
const int maxnode = 2600;
int n, m, k;

struct DLX {
    int n, m, idx;
    int U[maxnode], D[maxnode], R[maxnode], L[maxnode];
    int row[maxnode], col[maxnode], head[maxnode], siz[maxnode];

    void build(int _n, int _m) {
        n = _n, m = _m;
        for(int i = 0; i <= m; i++) {
            U[i] = D[i] = i;
            L[i] = i - 1, R[i] = i + 1;
        }
        R[m] = 0, L[0] = m;
        idx = m;
        memset(siz, 0, sizeof(siz));
        memset(head, -1, sizeof(head));
    }

    void link(int r, int c) {
        ++idx, ++siz[c];
        col[idx] = c, row[idx] = r;

        D[idx] = D[c];
        U[D[c]] = idx;
        U[idx] = c;
        D[c] = idx;
        if(head[r] < 0) head[r] = L[idx] = R[idx] = idx;
        else {
            R[idx] = R[head[r]];
            L[R[head[r]]] = idx;
            L[idx] = head[r];
            R[head[r]] = idx;
        }
    }
    
    void remove(int c) {
        for (int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }

    void resume(int c) {
        for (int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }

    bool vis[maxn];
    int estimate() {
        int res = 0;
        for(int i = R[0]; i != 0; i = R[i])
            vis[i] = false;

        for(int c = R[0]; c != 0; c = R[c])
            if(!vis[c]) {
                res++;
                vis[c] = true;
                for (int i = D[c]; i != c; i = D[i])
                    for (int j = R[i]; j != i; j = R[j])
                        vis[col[j]] = true;
            }
        return res;
    }

    bool dance(int dep) {
        if(dep + estimate() > k) return false;
        if(R[0] == 0) {
            return true;
        }
        int c = R[0];
        for (int i = R[0]; i != 0; i = R[i])
            if (siz[i] < siz[c])
                c = i;
        for(int i = D[c]; i != c; i = D[i]) {
            remove(i);
            for(int j = R[i]; j != i; j = R[j]) remove(j);
            if (dance(dep + 1)) return true;
            for(int j = L[i]; j != i; j = L[j]) resume(j);
            resume(i);
        }
        return false;
    }
} dlx;

struct Pos {
    double x, y;
} city[maxn], radar[maxm];

double radius[maxn * maxm], dis[maxm][maxn];

double distance(Pos& a, Pos& b) {
    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

int main() {
    int T;
    cin >> T;
    while(T--) {
        cin >> n >> m >> k;
        for(int i = 1; i <= n; i++)
            cin >> city[i].x >> city[i].y;
        for(int i = 1; i <= m; i++)
            cin >> radar[i].x >> radar[i].y;
        
        int totdis = 0;
        for(int i = 1; i <=m; i++)
            for(int j = 1; j <= n; j++)
                radius[totdis++] = dis[i][j] = distance(radar[i], city[j]);
        sort(radius, radius + totdis);

        int l = 0, r = totdis;
        while (l + 1 < r) {
            int mid = (l + r - 1) / 2;
            double middis = radius[mid];

            dlx.build(m, n);
            for(int i = 1; i <= m; i++)
                for(int j = 1; j <= n; j++)
                    if (dis[i][j] < middis + 1e-6)
                        dlx.link(i, j);
            
            if (dlx.dance(0)) r = mid + 1;
            else l = mid + 1;
        } 
        printf("%.6lf\n", radius[l]);
    }
}
View Code

 

 FZU1686 龙神的难题

思路:把敌人当作列,每个攻击的范围当作行。

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 16;
const int maxm = 16;
const int maxnode = 250;

struct DLX {
    int n, m, idx, tot;
    int U[maxnode], D[maxnode], R[maxnode], L[maxnode];
    int row[maxnode], col[maxnode], head[maxn], siz[maxm];

    void build(int _n, int _m) {
        n = _n, m = _m;
        for(int i = 0; i <= m; i++)
            U[i] = D[i] = i, L[i] = i - 1, R[i] = i + 1;
        L[0] = m, R[m] = 0;
        idx = m;
        tot = 255;
        memset(siz, 0, sizeof(siz));
        memset(head, -1, sizeof(head));
    }

    void insert(int r, int c) {
        idx++, siz[c]++;
        row[idx] = r, col[idx] = c;
        U[idx] = c, D[idx] = D[c];
        U[D[c]] = idx;
        D[c] = idx;
        if(head[r] < 0) head[r] = L[idx] = R[idx] = idx;
        else {
            L[idx] = L[head[r]];
            R[idx] = head[r];
            R[L[head[r]]] = idx;
            L[head[r]] = idx;
        }
    }

    void remove(int c) {
        for(int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }

    void recover(int c) {
        for(int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }

    bool vis[maxm];
    int estimate() {
        int res = 0;
        memset(vis, 0, sizeof(vis));

        for(int i = R[0]; i != 0; i = R[i])
            if(!vis[i]) {
                vis[i] = true;
                res++;
                for(int j = D[i]; j != i; j = D[j])
                    for(int k = L[j]; k != j; k = L[k])
                        vis[col[k]] = true;
            }
        return res;
    }

    void dance(int dep) {
        if(dep + estimate() > tot) return;
        if(R[0] == 0) {
            if(dep < tot) tot = dep;
            return;
        }
        int c = R[0];
        for(int i = R[0]; i != 0; i = R[i]) if(siz[i] < siz[c]) c = i;

        for(int i = D[c]; i != c; i = D[i]) {
            remove(i);
            for(int j = R[i]; j != i; j = R[j]) remove(j);
            dance(dep + 1);
            for(int j = L[i]; j != i; j = L[j]) recover(j);
            recover(i);
        }
    }
} dlx;

int monNum;
int monster[maxn][maxm];

int readData(int &n, int &m, int &n1, int &m1) {
    monNum = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++){
            int x;
            cin >> x;
            monster[i][j] = x == 0 ? 0 : ++monNum;
        }
    cin >> n1 >> m1;
    return monNum;
}

void addRange(int sx, int sy, int h, int w, int row) {
    for(int i = 0; i < h; i++)
        for(int j = 0; j < w; j++) {
            int x = sx + i, y = sy + j;
            if(monster[x][y]){
                dlx.insert(row, monster[x][y]);
            }
        }
}

int main() {
    int n, m, n1, m1;
    while(cin >> n >> m) {
        // readData
        int monNum = readData(n, m, n1, m1);

        // build DLX
        dlx.build((n - n1 + 1) * (m - m1 + 1), monNum);
        for(int i = 1; i <= n - n1 + 1; i++)
            for(int j = 1; j <= m - m1 + 1; j++) {
                addRange(i, j, n1, m1, (i - 1) * (m - m1 + 1) + j);
            }
        dlx.dance(0);
        cout << dlx.tot << endl;
    }
}
View Code

 

POJ1084 Square Destroyer

思路:找出每根火柴对应的方块,然后行为每根火柴,列为方块。另:POJ的编译器该更新了。

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 8;
const int maxm = 6;

struct DLX {
    static const int maxn = 2 * 6 * 7;
    static const int maxm = 6 * 7 * 13 / 6;
    static const int maxnode = maxn * maxm + maxm;
    int n, m, idx, tot;
    int U[maxnode], D[maxnode], R[maxnode], L[maxnode];
    int row[maxnode], col[maxnode], head[maxn], siz[maxm];

    void build(int _n, int _m) {
        n = _n, m = _m;
        for(int i = 0; i <= m; i++)
            U[i] = D[i] = i, L[i] = i - 1, R[i] = i + 1;
        L[0] = m, R[m] = 0;
        idx = m;
        tot = maxnode;
        memset(siz, 0, sizeof(siz));
        memset(head, -1, sizeof(head));
    }

    void insert(int r, int c) {
        idx++, siz[c]++;
        row[idx] = r, col[idx] = c;
        U[idx] = c, D[idx] = D[c];
        U[D[c]] = idx;
        D[c] = idx;
        if(head[r] < 0) head[r] = L[idx] = R[idx] = idx;
        else {
            L[idx] = L[head[r]];
            R[idx] = head[r];
            R[L[head[r]]] = idx;
            L[head[r]] = idx;
        }
    }

    void remove(int c) {
        for(int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
    }

    void recover(int c) {
        for(int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }

    bool vis[maxm];
    int estimate() {
        int res = 0;
        memset(vis, 0, sizeof(vis));

        for(int i = R[0]; i != 0; i = R[i])
            if(!vis[i]) {
                vis[i] = true;
                res++;
                for(int j = D[i]; j != i; j = D[j])
                    for(int k = L[j]; k != j; k = L[k])
                        vis[col[k]] = true;
            }
        return res;
    }

    void dance(int dep) {
        if(dep + estimate() > tot) return;
        if(R[0] == 0) {
            if(dep < tot) tot = dep;
            return;
        }
        int c = R[0];
        for(int i = R[0]; i != 0; i = R[i]) if(siz[i] < siz[c]) c = i;

        for(int i = D[c]; i != c; i = D[i]) {
            remove(i);
            for(int j = R[i]; j != i; j = R[j]) remove(j);
            dance(dep + 1);
            for(int j = L[i]; j != i; j = L[j]) recover(j);
            recover(i);
        }
    }
} dlx;

struct Squre {
    int u, d, l, r;
    int x, y;
} square[maxn][maxn];

int squareId;
vector<int> bar2square[2 * maxn * (maxn + 1)];

int removebar[2 * maxn * (maxn + 1)];
bool activeSquare[maxn * (maxn + 1) * (2 * maxn + 1) / 6];

void init(int n) {
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++) {
            square[i][j].x = i, square[i][j].y = j;
            square[i][j].u = (i - 1) * (2 * n + 1) + j;
            square[i][j].l = square[i][j].u + n;
            square[i][j].r = square[i][j].u + n + 1;
            square[i][j].d = i * (2 * n + 1) + j;
        }

    for(int i = 0; i <= 2 * n * (n + 1); i++) bar2square[i].clear();

    squareId = 0;
    for(int l = 1; l <= n; l++)
        for(int x = 1; x + l - 1 <= n; x++)
            for(int y = 1; y + l - 1 <= n; y++) {
                squareId++;
                for(int i = y; i < y + l; i++) {
                    bar2square[square[x][i].u].push_back(squareId);
                    bar2square[square[x + l - 1][i].d].push_back(squareId);
                }
                for(int i = x; i < x + l; i++) {
                    bar2square[square[i][y].l].push_back(squareId);
                    bar2square[square[i][y + l -1].r].push_back(squareId);
                }
            }
}

int main() {
    int T, n, k;
    cin >> T;
    while(T--) {
        cin >> n >> k;
        init(n);
        for(int i = 1; i <= k; i++) cin >> removebar[i];

        dlx.build(2 * n * (n + 1), squareId);
        for(int i = 1; i <= 2 * n *  (n + 1); i++) {
            memset(activeSquare, false, sizeof(activeSquare));
            for(int j = 1; j <= k; j++)
                for(int l = 0 ; l < bar2square[removebar[j]].size(); l++)
                    activeSquare[bar2square[removebar[j]][l]] = true;
            for(int j = 0; j < bar2square[i].size(); j++)
                activeSquare[bar2square[i][j]] = true;
            
            for(int j = 1; j <= squareId; j++)
                if(activeSquare[j])
                    dlx.insert(i, j);
        }
        dlx.dance(0);
        cout << dlx.tot << endl;
    }
}
View Code

 

POJ3074 Sudoku

思路:经典数独问题。

#include<iostream>
#include<cstring>
using namespace std;
static const int maxn = 9 * 9 * 9 + 5;
static const int maxm = 9 * 9 * 4 + 5;
static const int maxnode = maxn * maxm + maxm;

int grid[10][10];

struct DLX{
    int n, m, idx;
    int U[maxnode], D[maxnode], L[maxnode], R[maxnode];
    int row[maxnode], col[maxnode], head[maxn], siz[maxm];
    int row2num[maxn];

    void build(int _n, int _m){
        n = _n, m = _m;
        for(int i = 0; i <= m; i++)
            U[i] = D[i] = i, R[i] = i + 1, L[i] = i - 1;
        L[0] = m, R[m] = 0;
        idx = m;
        memset(head, 0, sizeof(head));
        memset(siz, 0, sizeof(siz));
    }

    void insert(int r, int c, int num) {
        idx++, siz[c]++;
        row2num[r] = num;
        row[idx] = r, col[idx] = c;
        U[idx] = c, D[idx] = D[c];
        U[D[c]] = idx;
        D[c] = idx;
        if(!head[r]) head[r] = R[idx] = L[idx] = idx;
        else {
            R[idx] = head[r], L[idx] = L[head[r]];
            R[L[head[r]]] = idx;
            L[head[r]] = idx;
        }
    }

    void remove(int c) {
        L[R[c]] = L[c], R[L[c]] = R[c];
        for(int i = D[c]; i != c; i = D[i])
            for(int j = L[i]; j != i; j = L[j]){
                U[D[j]] = U[j], D[U[j]] = D[j];
                siz[col[j]]--;
            }
    }

    void recover(int c) {
        for(int i = U[c]; i != c; i = U[i])
            for(int j = R[i]; j != i; j = R[j]){
                U[D[j]] = D[U[j]] = j;
                siz[col[j]]++;
            }
        L[R[c]] = R[L[c]] = c;
    }

    bool dance(int dep) {
        if(!R[0]) return true;

        int c = R[0];
        for(int i = R[0]; i != 0; i = R[i])
            if(siz[i] < siz[c])
                c = i;
        
        remove(c);
        for(int i = D[c]; i != c; i = D[i]) {
            for(int j = L[i]; j != i; j = L[j]) remove(col[j]), siz[col[j]]--;
            if(dance(dep + 1)) {
                if(col[i] <= 81)
                    grid[(col[i] - 1) / 9 + 1][(col[i] - 1) % 9 + 1] = row2num[row[i]];
                else {
                    for(int j = R[i]; j != i; j = R[j])
                        if(col[j] <= 81){
                            grid[(col[j] - 1) / 9 + 1][(col[j] - 1) % 9 + 1] = row2num[row[j]];
                            break;
                        }
                }
                return true;
            }
            for(int j = R[i]; j != i; j = R[j]) recover(col[j]), siz[col[j]]++;
        }
        recover(c);
        return false;
    }
} dlx;

char sudoku[90];

inline void insertNode(int r, int x, int y, int blk, int n){
    dlx.insert(r, x * 9 + y + 1, n);
    dlx.insert(r, 81 + y * 9 + n, n);
    dlx.insert(r, 162 + x * 9 + n, n);
    dlx.insert(r, 243 + blk * 9 + n, n);
}

int main() {
    while(cin >> sudoku) {
        if(sudoku[0] == 'e') break;
        int dotN = 0;
        for(int i = 0; i < 81; i++) if(sudoku[i] == '.') dotN++;

        dlx.build(dotN * 9 + 81 - dotN, 9 * 9 * 4);
        int rowN = 0;
        for(int i = 0; i < 81; i++) {
            int x = i / 9 , y = i % 9;
            int blk = x / 3 * 3 + y / 3;
            if(sudoku[i] == '.') {
                for(int j = 1; j <= 9; j++)
                    insertNode(++rowN, x, y, blk, j);
            }
            else {
                int num = sudoku[i] - '0';
                insertNode(++rowN, x, y, blk, num);
            }
        }
        dlx.dance(0);
        for(int i = 1; i <= 9; i++)
            for(int j = 1; j <= 9; j++)
                cout << grid[i][j];
        cout << endl;
    }
}
View Code

 

HDU4069 Squiggly Sudoku

题意:弯曲的九宫格。输入为格子数字+格子四周是否有围墙的数值。

思路:题目不难,但还是花了不少时间,基础不扎实。因为之前WA太多次了,DLX模板就抄了别人的,虽然最后发现不是模板问题。先找到联通的格子,再用dlx。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
static const int maxn = 9 * 9 * 9 + 5;
static const int maxm = 9 * 9 * 4 + 5;
static const int maxnode = maxn * maxm + maxm;
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int ans, tmpstk[maxn], stk[maxn], rowNum[maxn];

struct Grid {
    int num;
    int group;
    bool w[4];
} grid[10][10];

void findGroup() {
    int gid = 0;
    for(int i = 1; i <= 9; i++)
        for(int j = 1; j <= 9; j++) {
            if(grid[i][j].group) continue;

            gid++;
            queue<pair<int, int>> q;
            q.push({i, j});
            while(q.size()) {
                pair<int, int> p = q.front(); q.pop();
                grid[p.first][p.second].group = gid;
                for(int k = 0; k < 4; k++) {
                    if(!grid[p.first][p.second].w[k]) continue;
                    int nx = p.first + dx[k], ny = p.second + dy[k];
                    if(nx>=1 && nx<=9 && ny>=1 && ny<=9 && !grid[nx][ny].group) {
                        pair<int, int> np = {nx, ny};
                        q.push(np);
                    }
                }
            }

        }
}

void readData() {
    memset(grid, 0, sizeof(grid));
    int x;
    for(int i = 1; i <= 9; i++)
        for(int j = 1; j <= 9; j++) {
            cin >> x;
            grid[i][j].num = x & 15;
            grid[i][j].w[0] = !(x & 16);
            grid[i][j].w[1] = !(x & 64);
            grid[i][j].w[2] = !(x & 128);
            grid[i][j].w[3] = !(x & 32);
        }
}

struct DLX {
  static const int MAXSIZE = 1e5 + 10;
#define IT(i, A, x) for (i = A[x]; i != x; i = A[i])
  int n, m, tot, ansN, first[MAXSIZE + 10], siz[MAXSIZE + 10];
  int L[MAXSIZE + 10], R[MAXSIZE + 10], U[MAXSIZE + 10], D[MAXSIZE + 10];
  int col[MAXSIZE + 10], row[MAXSIZE + 10];
  void build(const int &r, const int &c) {
    n = r, m = c;
    for (int i = 0; i <= c; ++i) {
      L[i] = i - 1, R[i] = i + 1;
      U[i] = D[i] = i;
    }
    L[0] = c, R[c] = 0, tot = c;
    ansN = 0;
    memset(first, 0, sizeof(first));
    memset(siz, 0, sizeof(siz));
  }
  void link(const int &r, const int &c) {
    col[++tot] = c, row[tot] = r, ++siz[c];
    D[tot] = D[c], U[D[c]] = tot, U[tot] = c, D[c] = tot;
    if (!first[r])
      first[r] = L[tot] = R[tot] = tot;
    else {
      R[tot] = R[first[r]], L[R[first[r]]] = tot;
      L[tot] = first[r], R[first[r]] = tot;
    }
  }
  void remove(const int &c) {
    int i, j;
    L[R[c]] = L[c], R[L[c]] = R[c];
    IT(i, D, c) IT(j, R, i) U[D[j]] = U[j], D[U[j]] = D[j], --siz[col[j]];
  }
  void recover(const int &c) {
    int i, j;
    IT(i, U, c) IT(j, L, i) U[D[j]] = D[U[j]] = j, ++siz[col[j]];
    L[R[c]] = R[L[c]] = c;
  }
  bool dance(int dep) {
    if (!R[0]) {
      ans = dep;
      ansN++;
      memcpy(stk, tmpstk, sizeof(tmpstk));
      return 1;
    }
    int i, j, c = R[0];
    IT(i, R, 0) if (siz[i] < siz[c]) c = i;
    remove(c);
    IT(i, D, c) {
      tmpstk[dep] = row[i];
      IT(j, R, i) remove(col[j]);
      dance(dep + 1);
      if (ansN > 1) return 1;
      IT(j, L, i) recover(col[j]);
    }
    recover(c);
    return 0;
  }
#undef IT
} dlx;


int main() {
    int T;
    cin >> T;
    for(int t = 1; t <= T; t++) {
        readData();
        findGroup();

        dlx.build(9*9*9, 9*9*4);
        int rowN = 0;
        for(int i = 1; i <= 9; i++)
            for(int j = 1; j <= 9; j++){
                if(grid[i][j].num){
                    dlx.link(++rowN, (i - 1) * 9 + j);
                    dlx.link(rowN, 81 + (i - 1) * 9 + grid[i][j].num);
                    dlx.link(rowN, 162 + (j - 1) * 9 + grid[i][j].num);
                    dlx.link(rowN, 243 + (grid[i][j].group - 1) * 9 + grid[i][j].num);
                    rowNum[rowN] = grid[i][j].num;
                }
                else{
                    for(int k = 1; k <= 9; k++){
                        dlx.link(++rowN, (i - 1) * 9 + j);
                        dlx.link(rowN, 81 + (i - 1) * 9 + k);
                        dlx.link(rowN, 162 + (j - 1) * 9 + k);
                        dlx.link(rowN, 243 + (grid[i][j].group - 1) * 9 + k);
                        rowNum[rowN] = k;
                    }
                }
            }
        dlx.dance(0);

        cout << "Case " << t << ":" << endl;
        if(dlx.ansN == 0) cout << "No solution" << endl;
        else if(dlx.ansN > 1) cout << "Multiple Solutions" << endl;
        else {
            sort(stk, stk + ans);
            for(int i = 0; i < ans; i++){
                cout << rowNum[stk[i]];
                if((i + 1) % 9 == 0) cout << endl;
            }
        }
    }
    return 0;
}
View Code

 

HDU3335 Divisibility

思路:对DLX理解还是不深,这题自己没有想出来吃(¬︿̫̿¬☆)。注意到如果两个数相互divisible,那么这两个数一定不可以同时选,那我们建立一个n*n的重复覆盖DLX,当我们选择一个数a并把a列删除后,任意与a相互divisible的数b ,b列也会被删除。

#include<iostream>
#include<cstring>
using namespace std;
static const int maxn = 1005;
static const int maxm = 1005;
static const int maxnode = maxn * maxm + maxm;

long long num[maxn];

struct DLX {
    int n, m, idx, ansN;
    int U[maxnode], D[maxnode], L[maxnode], R[maxnode];
    int col[maxnode], row[maxnode], head[maxn], siz[maxm];

    void build(int r, int c){
        n = r, m = idx = c;
        for(int i = 0; i <= m; i++)
            U[i] = D[i] = i, L[i] = i - 1, R[i] = i + 1;
        L[0] = m, R[m] = 0;
        ansN = 0;
        memset(head, 0, sizeof(head));
        memset(siz, 0, sizeof(siz));
    }

    void link(int r, int c){
        idx++, siz[c]++;
        row[idx] = r, col[idx] = c;
        U[idx] = c, D[idx] = D[c];
        U[D[c]] = idx;
        D[c] = idx;
        if(!head[r]) head[r] = L[idx] = R[idx] = idx;
        else{
            L[idx] = L[head[r]], R[idx] = head[r];
            R[L[head[r]]] = idx;
            L[head[r]] = idx;
        }
    }

    void remove(int c){
        for(int i = D[c]; i != c; i = D[i])
            R[L[i]] = R[i], L[R[i]] = L[i];
    }

    void recover(int c){
        for(int i = U[c]; i != c; i = U[i])
            R[L[i]] = L[R[i]] = i;
    }

    int estimate(){
        int res = 0;
        for(int i = R[0]; i; i = R[i]) res++;
        return res;
    }

    void dance(int dep){
        if(dep + estimate() <= ansN) return;
        if(!R[0]){
            if(ansN < dep) ansN = dep;
            return;
        }
        int c = R[0];
        for(int i = R[0]; i; i = R[i])
            if(siz[i] < siz[c])
                c = i;
        
        for(int i = D[c]; i != c; i = D[i]){
            remove(i);
            for(int j = R[i]; j != i; j = R[j]) remove(j);
            dance(dep + 1);
            for(int j = L[i]; j != i; j = L[j]) recover(j);
            recover(i);
        }
    }
} dlx;

int main() {
    int T, n;
    cin >> T;
    while(T--){
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> num[i];

        dlx.build(n, n);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(num[i] % num[j] == 0 || num[j] % num[i] == 0)
                    dlx.link(i, j);
        
        dlx.dance(0);

        cout << dlx.ansN << endl;
    }
    return 0;
}
View Code

 

HDU4979 A simple math problem

题意:有N个号码,一张彩票含有M个号码,如果彩票含有R个中将号码,则为二等奖。求最少保证中奖的彩票数。

思路:重复覆盖。不想写选择数字,从网上抄了一个打表的AC代码。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
#include <ctime>
using namespace std;
 
int ans[8][8][8]={
    {
       {1}
    },
    {
        {2},
        {1,1}
    },
    {
        {3},
        {2,3},
        {1,1,1}
    },
    {
        {4},
        {2,6},
        {2,3,4},
        {1,1,1,1}
    },
    {
        {5},
        {3,10},
        {2,4,10},
        {2,3,4,5},
        {1,1,1,1,1}
    },
    {
        {6},
        {3,15},
        {2,6,20},
        {2,3,6,15},
        {2,3,4,5,6},
        {1,1,1,1,1,1}
    },
    {
        {7},
        {4,21},
        {3,7,35},
        {2,5,12,35},
        {2,3,5,9,21},
        {2,3,4,5,6,7},
        {1,1,1,1,1,1,1}
    },
    {
        {8},
        {4,28},
        {3,11,56},
        {2,6,14,70},
        {2,4,8,20,56},
        {2,3,4,7,12,28},
        {2,3,4,5,6,7,8},
        {1,1,1,1,1,1,1,1}
    }
};
int main()
{
    int n,m,r,T,tt=0;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&r);
        printf("Case #%d: %d\n",++tt,ans[n-1][m-1][r-1]);
    }
    return 0;
}
View Code

 

 HDU5046 Airport

思路:重复覆盖,和HDU2295相似。一直WA,好烦,代码就不给了。

posted @ 2021-01-06 15:42  Nanachi  阅读(75)  评论(0)    收藏  举报