链接:https://www.nowcoder.com/acm/contest/145/A
来源:牛客网
A题 Minimum Cost Perfect Matching
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
题目描述
You have a complete bipartite graph where each part contains exactly n nodes, numbered from 0 to n - 1 inclusive.
The weight of the edge connecting two vertices with numbers x and y is (bitwise AND).
Your task is to find a minimum cost perfect matching of the graph, i.e. each vertex on the left side matches with exactly one vertex on the right side and vice versa. The cost of a matching is the sum of cost of the edges in the matching. denotes the bitwise AND operator. If you're not familiar with it, see {https://en.wikipedia.org/wiki/Bitwise_operation#AND}.
输入描述:
The input contains a single integer n (1 ≤ n ≤ 5 * 105).
输出描述:
Output n space-separated integers, where the i-th integer denotes pi (0 ≤ pi ≤ n - 1, the number of the vertex in the right part that is matched with the vertex numbered i in the left part. All pi should be distinct. Your answer is correct if and only if it is a perfect matching of the graph with minimal cost. If there are multiple solutions, you may output any of them.
示例1
输入
复制
3
输出
复制
0 2 1
说明
For n = 3, p0 = 0, p1 = 2, p2 = 1 works. You can check that the total cost of this matching is 0, which is obviously minimal.
【题目大意】:左面一列分别为 0 ~ n-1 问你右面这一列匹配数字使得 一一对应之后权值最小权值是两个数字按位与的结果
思路:
这道题我们是找规律做的。按位与的结果一定可以等于0,所以我们找到怎么匹配可以使两两间按位与为0就好了。
从i_l = n-1 --> 0 找到 > i_l 的第一个2的幂次(2^x),让每次结点 i_l 匹配的 i_r 的和等于2^x-1,如果i_r找不到,那我们以目前 i_l 的值接着找 >= i_l 的第一个2的幂次。听着有点复杂,其实就是一层层找到匹配的2^x就好了,代码非常短,可以自己按照规律匹配一遍,很快就能明白。
举例:n = 11 时,2^4-1 = 15 是第一个大于 10 的数字。
10 ---- 5 i_l = 4时,2^3 -1 = 7 是第一个大于4的数字。
·9 ---- 6 4 ---- 3
8 ---- 7 3 ---- 4
7 ---- 8 i_l = 2时,2^2 - 1 = 3 是第一个大于2的数字。
6 ---- 9 2 ---- 1
5 ---- 10 1 ---- 2 .......依次类推 0 和 0 匹配
//舍弃 4 ---- 11 (此时,11是不存在的点,所以我们要找新的2的幂次)
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int mi[21];
for (int i=0; i<=20; i++)
mi[i] = pow(2,i) - 1;
int n;
while (cin >> n)
{
int a[n];
int tmp, pos;
for (int i=n-1; i>=0; i--)
{
pos = upper_bound(mi,mi+20,i) - mi;
if (mi[pos-1] == i)
pos = pos-1;
tmp = mi[pos];
int t = tmp-i;
for (int j=i; j>=t; j--)
{
a[j] = tmp - j;
if (j == t)
{
i = t;
break;
}
}
}
for (int i=0; i<=n-1; i++)
{
if (i)
printf(" ");
printf("%d",a[i]);
}
printf("\n");
}
return 0;
}