You are given a complete graph with N vertices, numbered from 1 to N.
InputThe first line of the input contains an integer T (1<= T <=10), the number of test cases. Then T test cases follow. Each test case consists of one line containing an integer N (2<=N<=200000).OutputFor each test case, you must output exactly 2 lines. You must print the weight of the minimum spanning tree in the 1st line. In the 2nd line, you must print N-1 space-separated integers f2, f3, … , fN, implying there is an edge between i and fi in your tree(2<=i<=N). If there are multiple solutions you must output the lexicographically smallest one. A tree T1 is lexicographically smaller than tree T2, if and only if the sequence f obtained by T1 is lexicographically smaller than the sequence obtained by T2.
Sample Input
2 3 2
Sample Output
1 1 1 0 1
题意:
有N个结点,两结点之间边的权值为两个点取与,比如说结点2和结点3之间的权值 W(2,3) = 10&11 = 10,问整个图的最小生成树
第一行输出最小生成树的权值和
第二行分别输出2到N节点连接的点(如果一个节点连接了2个点的话,需要输出小的那个)
分析:看到这道题目的时候当时一脸懵逼,最小生成树的权值之和好求,但是输出相连接结点的话。。。还是规律。。
二进制的10011最优的连接结点无疑是00100(二进制),,本质就是找到第一个非1的位置,其他位置都为0就OK.
但是看一个特例:111的最有连接结点是1000,但是如果N最大为7(十进制),那就没有8(二进制1000)来进行配对了,因此111只能被迫与1进行配对。
总结下来:第一行最小生成树的权值之和只能是1或者0,然后特例只要判断n+1是否为2的幂指数就可以。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = 2e5+10; 7 #define LL long long 8 #define INF 0x3f3f3f3f 9 int T; 10 int a[maxn]; 11 bool judge(int x){ 12 int k=x&(x-1); 13 if(!k)return true; 14 return false; 15 } 16 int ft(int x){ 17 int ans=1; 18 while(1){ 19 int k=x&1; 20 x>>=1; 21 if(!k) break; 22 ans<<=1; 23 } 24 return ans; 25 } 26 27 int main(){ 28 scanf("%d",&T); 29 while(T--){ 30 int n; 31 scanf("%d",&n); 32 memset(a,0,sizeof(a)); 33 if(judge(n+1)) printf("1 "); 34 else printf("0 "); 35 for(int i=2;i<=n;i++){ 36 int k=ft(i); 37 if(k>n) printf("1"); 38 else printf("%d",k); 39 if(i==n) printf(" "); 40 else printf(" "); 41 } 42 } 43 44 return 0; 45 }