链接:https://www.nowcoder.com/acm/contest/116/H
来源:牛客网
来源:牛客网
XOR
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
Once there was a king called XOR, he had a lot of land. Because of his name, he likes to play XOR games. One day, he whimpered and wanted to establish N cities on that vast expanse of land, numbered 0, 1, 2..., N-1. He wanted to connect all the cities. If city A can reach City B through zero or one or several cities, then A and B are connected. The cost of repairing a road in City A and City B is the XOR value of number of City A and number of City B. This King XOR wanted to figure out the minimum cost for connecting all of the N cities. Of course, like a fairy tale read as a child, there will be corresponding rewards after helping the king. If you help the king solve his problems, he will improve your ranking in the competition.
输入描述:
There are multi test caseseach test cases contains an integer N (2 ≤N≤ 20000), the number of cities the king wants to establish.
输出描述:
For each test case, print the minimum cost for connecting all of the N cities in one line.
示例1
输入
4
输出
4
说明
The weightof the minimum cost is 1+2+1=4 In the Sample Example.
题目大意:有n个城市,编号为0~n-1,让你求出这n个城市连通的最小消耗(有点类似最小生成树),两个城市连通的消耗为这两个城市编号的最小异或值。
解题思路:我们首先来解释什么是异或值,例如4(100)和5(101)的异或值为1(001),就是11/00=0,10=1,好了我们来解释下样例:0(00)、1(01)、2(10)、3(11),我们先连0、1(花费为1),然后再连0、2(花费为2),最后再连2、3(花费为1),如果你列多一点数据你就会发现,一定是从0往后连花费是最小的。
解法1(暴力+贪心32ms):我们可以暴力枚举每个城市连通的花费,然后贪心取最小值即可,当然了我们不可能从0开始枚举,每个城市连通时的最小花费二进制的最高位一定时一样的才是最小花费(贪心),所以我们只要从一样长的位数开始枚举就可以了,大大降低了复杂度。
AC代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<math.h> #include<stdlib.h> #include<queue> #include<map> #define bug printf("--------"); using namespace std; typedef long long LL; int n, vis[10]; int check(int x) //位数判断 { int cnt = 0; while(x > 0) { cnt ++; x /= 2; } return cnt; } int main() { while(~scanf("%d", &n)) { int ans = 0; for(int i = 1; i < n; i ++) { int s = check(i); if(i == 1<<(s-1)) ans += i; //刚好是第一个(2、4、8、16...) else { int u = 100000; for(int j = 1<<(s-1); j < i; j ++) { u = min(u, i^j); //贪心 i^j为i和j的异或值 } ans += u; } } printf("%d\n", ans); } return 0; }
解法2(规律发现4ms):在贪心的过程中牛逼的人会发现,每个城市的的最小花费刚好就是该城市编号化为2进制后最低位的1独立出来的值(1010->10、100110->10、111->1),然后我们有个运算刚好就是求最低为1独立出来的值:x&(-x),-x的是x的二进制按位取反再+1(1010->0101+1=0110)
AC代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<math.h> #include<stdlib.h> #include<queue> #include<map> #define bug printf("--------"); using namespace std; typedef long long LL; int n; int main() { while(~scanf("%d", &n)) { int ans = 0; for(int i = 0; i < n; i ++) ans += i&(-i); printf("%d\n", ans); } return 0; }