kuangbin专题三:Dancing Links
前:上个专题有点麻烦,暂时不想写了。
思路:这题不是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; }
思路:二维的Dancing Links问题,感觉搜索也可以做。我们需要确保任意两个piece互不覆盖,但普通DLX只能处理一维情况,所以我们要稍微变化一下。把n行m列的矩阵展开成n×m的一维数组,那么每个piece都能以一个n×m的一维数组表示,有piece的地方为1,没有为0。问题就转换成从p个piece里找到一个精确覆盖。
思路:行数为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]); } }
思路:把敌人当作列,每个攻击的范围当作行。
#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; } }
思路:找出每根火柴对应的方块,然后行为每根火柴,列为方块。另: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; } }
思路:经典数独问题。
#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; } }
题意:弯曲的九宫格。输入为格子数字+格子四周是否有围墙的数值。
思路:题目不难,但还是花了不少时间,基础不扎实。因为之前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; }
思路:对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; }
题意:有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; }
思路:重复覆盖,和HDU2295相似。一直WA,好烦,代码就不给了。

浙公网安备 33010602011771号