20200915 专题:舞蹈链(DLX)

总览:

解决覆盖问题
用十字交叉双向循环链表优化搜索复杂度
在这里插入图片描述

T1 P4929 【模板】舞蹈链(DLX)

思路:
板子题

代码:

#include <bits/stdc++.h>
using namespace std;

#define re register
#define LL long long
typedef unsigned int uint;
typedef unsigned long long ull;
#define pb push_back
#define mp make_pair

namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch()                                                                 \
  (_p1 == _p2 &&                                                             \
           (_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
       ? EOF                                                                 \
       : *_p1++)
inline int in() {
  int s = 0, f = 1;
  char x = ch();
  for (; x < '0' || x > '9'; x = ch())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}
char buf_[1 << 21];
int p1_ = -1;
inline void flush() {
  fwrite(buf_, 1, p1_ + 1, stdout);
  p1_ = -1;
}
inline void pc(char x) {
  if (p1_ == (1 << 21) - 1) flush();
  buf_[++p1_] = x;
}
inline void out(int x) {
  char k[30];
  int pos = 0;
  if (!x) {
    pc('0');
    return;
  }
  if (x < 0) {
    pc('-');
    x = -x;
  }
  while (x) {
    k[++pos] = (x % 10) | 48;
    x /= 10;
  }
  for (int i = pos; i; i--) pc(k[i]);
  return;
}
inline void out(string x) {
  int k = x.size();
  for (int i = 0; i < k; i++) pc(x[i]);
}
}  // namespace IO
using namespace IO;

const int A = 505;
int n, m;
struct node {
  int ls, rs, up, dn, x, y;
} p[A * A];
int tot = -1;
int fx[A], lx[A];
int num[A];
int ans[A], top;

inline void remove(int x) {
  p[p[x].ls].rs = p[x].rs;
  p[p[x].rs].ls = p[x].ls;
  for (int i = p[x].dn; i != x; i = p[i].dn) {
    for (int j = p[i].rs; j != i; j = p[j].rs) {
      p[p[j].up].dn = p[j].dn;
      p[p[j].dn].up = p[j].up;
      num[p[j].y]--;
    }
  }
  return;
}

inline void restore(int x) {
  for (int i = p[x].up; i != x; i = p[i].up) {
    for (int j = p[i].ls; j != i; j = p[j].ls) {
      p[p[j].dn].up = j;
      p[p[j].up].dn = j;
      num[p[j].y]++;
    }
  }
  p[p[x].ls].rs = x;
  p[p[x].rs].ls = x;
  return;
}

inline int DFS(int now) {
  if (!p[0].rs) return 1;
  int pos = p[0].rs;
  for (int i = p[0].rs; i; i = p[i].rs)
    if (num[i] < num[pos]) pos = i;
  remove(pos);
  for (int i = p[pos].dn; i != pos; i = p[i].dn) {
    ans[++top] = p[i].x;
    for (int j = p[i].rs; j != i; j = p[j].rs) remove(p[j].y);
    if (DFS(now + 1)) return 1;
    top--;
    for (int j = p[i].ls; j != i; j = p[j].ls) restore(p[j].y);
  }
  restore(pos);
  return 0;
}

signed main() {
  n = in(), m = in();
  for (int i = 0; i <= m; i++)
    p[++tot].ls = i - 1, p[tot].rs = i + 1, p[tot].up = p[tot].dn = i;
  p[0].ls = m, p[m].rs = 0;
  for (int i = 1; i <= n; i++) {
    int fx = tot + 1;
    for (int j = 1; j <= m; j++) {
      int u = in();
      if (!u) continue;
      ++tot;
      p[tot].ls = tot - 1, p[tot].rs = tot + 1;
      p[tot].up = p[j].up, p[tot].dn = j;
      p[p[tot].up].dn = tot, p[j].up = tot;
      p[tot].x = i, p[tot].y = j;
      num[j]++;
    }
    p[tot].rs = fx, p[fx].ls = tot;
  }
  if (DFS(0))
    for (int i = 1; i <= top; i++) {
      out(ans[i]), pc(' ');
      pc('\n');
    }
  else
    out("No Solution!\n");
  flush();
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值