题目:    可以用一个网络地址和一个子网掩码描述一个子网(即连续的IP地址范围)。其中子网 掩码包含32个二进制位,前32-n位为1,后n位为0,网络地址的前32-n位任意,后n位为0。 所有前32-n位和网络地址相同的IP都属于此网络。
例如,网络地址为194.85.160.176(二进制为11000010|01010101|10100000|10110000), 子网掩码为255.255.255.248(二进制为11111111|11111111|11111111|11111000),则该子网 的IP地址范围是194.85.160.176~194.85.160.183。输入一些IP地址,求最小的网络(即包含IP 地址最少的网络),包含所有这些输入地址。
例如,若输入3个IP地址:194.85.160.177、194.85.160.183和194.85.160.178,包含上述3 个地址的最小网络的网络地址为194.85.160.176,子网掩码为255.255.255.248

链接: https://vjudge.net/problem/UVA-1590

解:二进制的使用

每个ip有4个数字,从左开始找到第一个数字不是所有ip都一样,转化为8位二进制

从左数,到哪一位二进制码不同,记为mark;则对于地址是mark前与原码相同,mark后都为0,而对于子网掩码是mark前都为1,mark 后都为0

有个非常巧妙的方法求地址,就是  地址 = mask & 原码值;

#include<bits/stdc++.h>
using namespace std;

int f[9] = {255, 254, 252, 248, 240, 224, 192, 128, 0};
int ip[4][1024],s[4],ans[4];
int m;

int main()
{
	while(~scanf("%d",&m))
	{
		memset(ip, 0, sizeof(ip));
		for(int i = 0; i < m; ++i)
			scanf("%d.%d.%d.%d",&ip[0][i],&ip[1][i],&ip[2][i],&ip[3][i]);
		for(int i = 0; i < 4; i++)
		{
			int dif = 0, x, j;
			int p,q;
			sort(ip[i], ip[i] + m);
			p = ip[i][m - 1];
			q = ip[i][0];
			for(j = 1; j <= 8; j++)
            {
                if(p % 2 != q % 2) dif = j;
                p /= 2;
                q /= 2;
            }
			s[i] = f[dif];
			ans[i] = ip[i][0] & s[i];
		}
		for(int i = 0; i < 4; ++i)
			if(s[i] != 255)
			{
				for(int j = i + 1; j < 4; j++)
				{
					s[j] = 0;
					ans[j] = 0;
				}
				break;
			}
		printf("%d.%d.%d.%d\n",ans[0], ans[1], ans[2], ans[3]);
		printf("%d.%d.%d.%d\n",s[0], s[1], s[2], s[3]);
	}
	return 0;
}