首先推几个结论:
- 原编号为
的点新编号为
,可使字典序最小。
- 距离新编号为
的点,最短距离为
的点,新编号中有
个
。考虑从
号点开始走,每次增加一个
,最少
步后才能走出
个
,且该距离为最小距离,若不如此走,分两种情况:将新编号中
位走成
或将新编号中
位走成
,则都需要走回头路,因此距离更长。
- 新编号含有
个
的点,仅与若干个含有
个
的点与含有
个
的点联通,且若干个含有
个
的点新编号的或和即为该点新编号。考虑含有
个
的点,根据第二条结论发现它们离
的距离为
,则其直接与含有
个
的点联通的路径即为其最短路。因此可以推出,这些点与含有
个
的点仅相差一个包含在
个
中的
,且每个点相差的
位置都不同。这些点或起来,即可得到含有
个
的点的新编号。
- 交换二进制位列,对图性质无影响。例如有点:101 001 010,将第一列交换至第三列,第二列交换至第一列,第三列交换至第二列,新编号为:011 010 100,而原先的图关系不变。
- 将所有点的二进制编号看做矩阵,行为点原编号,列为二进制位,值为对应的
或
,那么交换任意两列,图的性质不变。由于字典序,应当让原编号小的对应的
的列排在低位。
可以看到,推出的前三个结论与距离密切相关。
整个图可以看做一圈一圈的、距离依次加一的几层,而用该层编号即可推出下层编号,因此可以对原图做一遍宽度优先搜索。
将与原 号点相连的点随意分配初始编号,进行一次宽度优先搜索,即可找出一组可行解。
再根据后两个结论,将列进行排序,即可找出最优解。
#include <cstdio> #include <algorithm> #include <ctype.h> const int bufSize = 1e6; inline char nc() { #ifdef DEBUG return getchar(); #endif static char buf[bufSize], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, bufSize, stdin), p1 == p2) ? EOF : *p1++; } template <typename T> inline T read(T &r) { static char c; r = 0; for (c = nc(); !isdigit(c);) c = nc(); for (; isdigit(c); c = nc()) r = r * 10 + c - 48; return r; } const int maxn = 1e6 + 100, maxm = 5e6 + 100; int T, n, m; struct node { int to, next; } E[maxm]; int head[maxn], tot; inline void add(const int &x, const int &y) { E[++tot].next = head[x], E[tot].to = y, head[x] = tot; } int q[maxn], qt, qh; int f[maxn], vis[maxn], inq[maxn]; struct A { bool s[maxn]; int id; } P[22]; bool cmp(const A &a, const A &b) { for (int i = 1; i <= (1 << n); ++i) if (a.s[i] != b.s[i]) return a.s[i] > b.s[i]; return 1; } int main() { read(T); while (T--) { read(n), read(m); qh = 1, qt = 0; tot = 0; for (int i = 1; i <= (1 << n); ++i) vis[i] = f[i] = inq[i] = head[i] = 0; for (int i = 1; i <= m; ++i) { int a, b; read(a), read(b); add(a, b), add(b, a); } vis[1] = 1; for (int p = head[1], t = 0; p; p = E[p].next) { int v = E[p].to; f[v] = 1 << (t++); q[++qt] = v; } while (qt >= qh) { int u = q[qh++]; vis[u] = 1,inq[u] = 0; for (int p = head[u]; p; p = E[p].next) { int v = E[p].to; if (vis[v]) continue; f[v] |= f[u]; if (!inq[v]) q[++qt] = v, inq[v] = 1; } } for (int i = 0; i < n; ++i) P[i].id = i; for (int i = 1; i <= (1 << n); ++i) for (int j = 0; j < n; ++j) P[j].s[i] = (f[i] >> j) & 1; std::sort(P, P + n, cmp); for (int i = 1; i <= (1 << n); ++i) { int res = 0; for (int j = 0; j < n; ++j) if (P[j].s[i]) res |= (1 << j); printf("%d ", res); } putchar('\n'); } return 0; }