UVA 1590 IP Networks 位操作解题

这个题就是求出若干个32位2进制数的前多少位相同,用字符串处理可以做,但是用位操作更为简单。

首先,

与操作的特性是 0&0=0,1&1=1,0&1=0,假若a,b两个数进行与操作,那么相同数字的位依然保持不变,不同数字的位变为0(不同数字一定一个是0,一个是1)

或操作的特性是 0|0=0,1|1=1,0|1=1,假若a,b两个数进行与操作,那么相同数字的位依然保持不变,不同数字的位变为1(不同数字一定一个是0,一个是1)

假设
a=10101010b
b=11001100b
c=11110000b

d=a&b&c=10000000b
e=a|b|c=11111110b

异或的特性是,若操作数对应位置的数相同,则在该位置输出0,否则输出1;


f=d^e=01111110


因为与操作和或操作保持了原来相同数字的位不变,不同数字的位分别改变为0和1,所以将与和或操作的结果进行异或操作,所有为1的位,即为原来的所有数存在差别的位

bit = log2(f * 2 + 1);

bit即为从第一个有差别的数字起,到末尾的位数。此时我们可以根据这个位数,求得对应的掩码。方法是先将掩码置为全1,先右移bit位再左移bit位

最终完整的代码为:

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <cmath>
using namespace std;
int main(){
	long long ip_or;//所有ip"或"的结果
	long long ip_and;//所有ip"与"之后的结果
	long long ip_xor;//"与"与"或"的结果再求异或
	long long mask;//存储掩码
	long long segment;//存储网段
	int n;			 //循环读ip次数
	//暂存数据
	long long temp;
	long long num1, num2, num3, num4;
	char ch;

	while (cin >> n){
		//初始化
		cin >> num1 >> ch >> num2 >> ch >> num3 >> ch >> num4;
		temp = 0;
		temp += (num1 << 24) + (num2 << 16) + (num3 << 8) + num4;
		ip_or = ip_and = temp;
		while (--n){
			//读取所有的ip,求or和and
			cin >> num1 >> ch >> num2 >> ch >> num3 >> ch >> num4;
			temp = 0;
			temp += (num1 << 24) + (num2 << 16) + (num3 << 8) + num4 ;
			ip_or = ip_or | temp;
			ip_and = ip_and&temp;
		}
		//求xor
		ip_xor = ip_or^ip_and;
		//求出从左到右第一个不同的数字的位置(位置是从右往左数的)
		int bit = log2(ip_xor * 2 + 1);
		mask = 0xFFFFFFFF;
		//将掩码末尾的bit位置0
		mask = (mask >> bit) << bit;
		//网段是随便一个ip与掩码的按位与
		segment = ip_or&mask;
		//输出结果
		cout << ((segment >> 24) & 0x0FF) << "." << ((segment >> 16) & 0x0FF) << "." << ((segment >> 8) & 0x0FF) << "." << (segment & 0x0FF) << endl;
		cout << ((mask >> 24) & 0x0FF) << "." << ((mask >> 16) & 0x0FF) << "." << ((mask >> 8) & 0x0FF) << "." << (mask & 0x0FF) << endl;
	}
	return 0;
}

值得一提的是,如果变量unsigned类型,即使考虑了ip_xor * 2 + 1的溢出问题,对掩码是80000000和00000000单独讨论,依然无法AC,改为long long即可AC


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值