UVa 1590 IP Networks(IP 网络)

本文详细介绍了IP地址子网划分的概念、方法以及如何通过位运算求解子网掩码和子网内最小IP的步骤。通过实例分析,帮助读者理解并掌握IP地址子网划分的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Download as PDF

Alex is administrator of IP networks. His clients have a bunch of individual IP addresses and he decided to group all those IP addresses into the smallest possible IP network.

Each IP address is a 4-byte number that is written byte-by-byte in a decimal dot-separated notation ``byte0.byte1.byte2.byte3" (quotes are added for clarity). Each byte is written as a decimal number from 0 to 255 (inclusive) without extra leading zeroes.

IP network is described by two 4-byte numbers - network address and network mask. Both network address and network mask are written in the same notation as IP addresses.

In order to understand the meaning of network address and network mask you have to consider their binary representation. Binary representation of IP address, network address, and network mask consists of 32 bits: 8 bits for byte0 (most significant to least significant), followed by 8 bits for byte1, followed by 8 bits for byte2, and followed by 8 bits for byte3.

IP network contains a range of 2n IP addresses where 0$ \le$n$ \le$32 . Network mask always has 32 - n first bits set to one, and n last bits set to zero in its binary representation. Network address has arbitrary 32 - n first bits, and n last bits set to zero in its binary representation. IP network contains all IP addresses whose 32 - n first bits are equal to 32 - n first bits of network address with arbitrary n last bits. We say that one IP network is smaller than the other IP network if it contains fewer IP addresses.

For example, IP network with network address 194.85.160.176 and network mask 255.255.255.248 contains 8 IP addresses from 194.85.160.176 to 194.85.160.183 (inclusive).

Input 

The input file will contain several test cases, each of them as described below.

The first line of the input file contains a single integer number m(1$ \le$m$ \le$1000) . The following m lines contain IP addresses, one address on a line. Each IP address may appear more than once in the input file.

Output 

For each test case, write to the output file two lines that describe the smallest possible IP network that contains all IP addresses from the input file. Write network address on the first line and network mask on the second line.

Sample Input 

3 
194.85.160.177 
194.85.160.183 
194.85.160.178

Sample Output 

194.85.160.176 
255.255.255.248
	
	

接到训练题后翻了一遍,第一眼就瞅上这个题了,IP地址,之前培训过几天计算机网络知识,知道子网的划分方法。做题之前首先要了解到什么是子网掩码,子网掩码是子网划分的依据,它跟IP地址一样,长度也是32位,点分十进制表示,每部分0~255,但是跟IP地址不同的是,子网掩码只能由连续的1和0组成,也就是说,把这32位从任意位置分开,左边只能全是1,右边只能全是0。比如11111111.11111111.11111111.11111000(255.255.255.248)就是合法的子网掩码,而11000000.10101000.00000001.00000000(192.168.1.0)就不合法(可以尝试一下在计算机上给网络连接手动分配子网掩码,看看它会怎么提示你)。给定两个IP,假设其子网掩码二进制有x个连续的1,则如果这两个IP的二进制前x位对应相等,那么这两个IP就属于同一网段,也就是属于同一个子网。

如果给定一个子网掩码和一个IP,就可以求出这个IP所在子网的最小IP,方法是将IP的二进制与子网掩码的二进制进行按位与运算,原理是,子网掩码为1的二进制位,要求子网内所有IP的这一位必须全部相等,而子网掩码为0的位不作要求,也就是说,给定一个IP,子网内最小IP对应的子网掩码为1的位必须跟给定IP一样,按位与的时候,给定IP与子网掩码是1的位按位与后的结果不变,子网掩码0的位按位与后为0(恰好是最小),这样按位与运算结束后,得到的IP就是子网内最小IP(说的我自己都有点晕乎了,想弄明白这个,必须了解位运算和子网掩码的相关知识)。

说了这么多,都只是预备知识,下面可以切入正题,给定一些IP地址,求出子网掩码和子网内最小IP。

根据上面所说,这个题只要求出子网掩码,然后与给定的任意IP进行按位与运算,就可以得到最小IP了。那么现在关键就是求子网掩码了,既然给定的这一些IP都是一个网段的,那么找到这些IP里的最小IP和最大IP,然后找到这两个IP的二进制从左往右看哪一位最先出现不同(异或运算可解),就可以知道子网掩码里有几个连续的1,自然就得到子网掩码了,然后最小IP便迎刃而解。所以这个题其实很简单,只要了解点IP地址相关知识即可。

实现方面,写了个ip类,有四部分,分别对应点分十进制的四部分,重载<运算符,sort排序后找到给定IP里的最大和最小,这两个IP每部分依次异或运算得到子网掩码连续的1的个数,得到子网掩码,与任意IP按位与,得到最小IP,个人认为这题的精华是位运算的应用,代码如下:

#include <cstdio>
#include <algorithm>

using namespace std;

struct ip	//定义ip类,四个部分
{
	int part[4];
	ip()	//默认构造方法,全为0
	{
		part[0]=part[1]=part[2]=part[3]=0;
	}
	void print()	//把输出定义成了成员函数
	{
		printf("%d.%d.%d.%d\n",part[0],part[1],part[2],part[3]);
	}
	bool operator < (const ip a)const //重载小于运算,方便用sort排序找到最大最小
	{
		for(int i=0;i<4;i++)
			if(part[i]!=a.part[i])
				return part[i]<a.part[i];
		return false;
	}
}add[1010];

int toBit(int n);
int getMinBit(ip a,ip b);	//求子网掩码连续1的位数

int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		ip minn,mask;
		for(int i=0;i<n;i++)
			scanf("%d.%d.%d.%d",&add[i].part[0],&add[i].part[1],&add[i].part[2],&add[i].part[3]);
		sort(add,add+n);
		int bit=getMinBit(add[0],add[n-1]);	//将IP最大和最小值传入函数求出子网掩码连续1的个数
		int site=(bit-1)/8;	//得到子网掩码第一个0所在的部分(点分十进制四部分)
		for(int i=0;i<site;i++)	//这部分之前的部分都是255(即11111111)
			mask.part[i]=255;
		int m=8-bit+(site*8);	//m为第一个0所在部分那8位中有几个0
		mask.part[site]=(255>>m)<<m;	//255(11111111)先右移m位再左移m位即可得8-m个1和m个0,经过此步即可得子网掩码
		for(int i=0;i<4;i++)
			minn.part[i]=add[0].part[i]&mask.part[i];	//子网掩码与任意IP每部分按位与运算得到子网内最小IP
		minn.print();
		mask.print();
	}

	return 0;
}
int toBit(int n)	//给定一个十进制整数,得到整数的二进制位数
{
	int res;
	for(res=0;n;res++)
		n/=2;
	return res;
}
int getMinBit(ip a,ip b)
{
	int res=32;
	for(int i=0;i<4;i++)
		if(a.part[i]!=b.part[i])	//对应部分不等,则找出二进制位从第几位开始出现不等
		{
			res=8-toBit(a.part[i]^b.part[i]);	//异或运算,两操作数对应二进制位不等得1,反之得0,根据异或结果可知出现不等的最左位置
			res+=(i*8);	//得到子网掩码连续1的个数
			break;
		}
	return res;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值