首先推几个结论:
- 原编号为
的点新编号为
,可使字典序最小。
- 距离新编号为
的点,最短距离为
的点,新编号中有
个
。考虑从
号点开始走,每次增加一个
,最少
步后才能走出
个
,且该距离为最小距离,若不如此走,分两种情况:将新编号中
位走成
或将新编号中
位走成
,则都需要走回头路,因此距离更长。
- 新编号含有
个
的点,仅与若干个含有
个
的点与含有
个
的点联通,且若干个含有
个
的点新编号的或和即为该点新编号。考虑含有
个
的点,根据第二条结论发现它们离
的距离为
,则其直接与含有
个
的点联通的路径即为其最短路。因此可以推出,这些点与含有
个
的点仅相差一个包含在
个
中的
,且每个点相差的
位置都不同。这些点或起来,即可得到含有
个
的点的新编号。
- 交换二进制位列,对图性质无影响。例如有点: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;
} 
京公网安备 11010502036488号