首先推几个结论:

  1. 原编号为 的点新编号为 ,可使字典序最小。
  2. 距离新编号为 的点,最短距离为 的点,新编号中有 。考虑从 号点开始走,每次增加一个 ,最少 步后才能走出 ,且该距离为最小距离,若不如此走,分两种情况:将新编号中 位走成 或将新编号中 位走成 ,则都需要走回头路,因此距离更长。
  3. 新编号含有 的点,仅与若干个含有 的点与含有 的点联通,且若干个含有 的点新编号的或和即为该点新编号。考虑含有 的点,根据第二条结论发现它们离 的距离为 ,则其直接与含有 的点联通的路径即为其最短路。因此可以推出,这些点与含有 的点仅相差一个包含在 中的 ,且每个点相差的 位置都不同。这些点或起来,即可得到含有 的点的新编号。
  4. 交换二进制位列,对图性质无影响。例如有点:101 001 010,将第一列交换至第三列,第二列交换至第一列,第三列交换至第二列,新编号为:011 010 100,而原先的图关系不变。
  5. 将所有点的二进制编号看做矩阵,行为点原编号,列为二进制位,值为对应的 ,那么交换任意两列,图的性质不变。由于字典序,应当让原编号小的对应的 的列排在低位。

可以看到,推出的前三个结论与距离密切相关。

整个图可以看做一圈一圈的、距离依次加一的几层,而用该层编号即可推出下层编号,因此可以对原图做一遍宽度优先搜索。

将与原 号点相连的点随意分配初始编号,进行一次宽度优先搜索,即可找出一组可行解。

再根据后两个结论,将列进行排序,即可找出最优解。

#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;
}