UVa 1590 IP Networks (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地址:194.85.160.177、 194.85.160.183、 194.85.160.178,包含上述三个地址的最小网络的网络地址为194.85.160.176,子网掩码是255.255.255.248


思路:

十进制--->二进制--->十进制

由二进制可以得到公共的二进制表示,则子网掩码就是将这些公共部分全部用1表示,剩余右边全用0补。而最小地址则是公共范围相同,剩余右边全用0补。

十进制和二进制的切割转化,可以用sscanf函数和sprintf函数


下面代码部分注释是为了辅助调试 :)

#include <stdio.h>
#include <string.h>
#include <math.h>
#define maxn 1010
char s[maxn][35],s1[4][10], s2[20];
char q[35], w[4][10], mins[35];
char z[35], h[4][10], ans[35];
int a[4],d1[4],d2[4];
int m;
void num_to_str(int n, char b[])
{//将整数转换成相应的二进制字符串
	int k = 8;
	b[k--] = '\0';
	while (k>=0)
	{
		b[k] = n % 2 + '0';
		n /= 2;
		k--;
	}
}
int compare(char x[], char y[], int n)
//比较两个字符串的前n个字符返回从第一个不同的字符的前一个位置,完全相同返回n
{
	int i;
	for ( i = 0;i <= n;i++)
		if (x[i] != y[i]) break;
	return (i - 1);
}
int str_to_num(char d[])
{//将二进制字符串转换成对应整数
	int res = 0;
	for (int i = 0;i < 8;i++)
		res = res * 2 + d[i] - '0';
	return res;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	while (~scanf("%d", &m))
	{
		for (int i = 0;i < m;i++)
		{
			scanf("%s", s2);
			for (int j = 0;s2[j];j++)
				if (s2[j] == '.') s2[j] = ' ';
			//puts(s2);
			sscanf(s2, "%d %d %d %d", &a[0], &a[1], &a[2], &a[3]);
			//printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]);
			for (int j = 0;j < 4;j++)
			{
				num_to_str(a[j], s1[j]);
				//printf("%s ", s1[j]);
				if (j) strcat(s[i], s1[j]);
				else strcpy(s[i], s1[j]);//转化成二进制形式IP地址
			}
			//putchar('\n');
			//puts(s[i]);
		}
		int r = 31;
		for (int i = 0;i < m - 1;i++)
			r = compare(s[i], s[i + 1],r);//寻找相同的位数
		int l = 0;
		for (int j = 0;j<=31;j++)
		{
			if (j <= r) q[l++] = s[0][j];
			else q[l++] = '0';
			if ((j + 1) % 8 == 0 && j < 31) q[l++] = ' ';
		}
		//puts(q);
		sscanf(q, "%s %s %s %s", w[0], w[1], w[2], w[3]);
		for (int j = 0;j < 4;j++)
			d1[j]=str_to_num(w[j]);
		sprintf(mins, "%d.%d.%d.%d", d1[0], d1[1], d1[2], d1[3]);//转化成十进制形式IP地址
		int f = 0;
		for (int j = 0;j <= 31;j++)
		{
			if (j <= r) z[f++] = '1';
			else z[f++] = '0';
			if ((j + 1) % 8 == 0 && j<31) z[f++] = ' ';
		}
		//puts(z);
		sscanf(z, "%s %s %s %s", h[0],h[1], h[2], h[3]);
		for (int j = 0;j < 4;j++)
			d2[j]=str_to_num(h[j]);
		sprintf(ans, "%d.%d.%d.%d", d2[0], d2[1], d2[2], d2[3]);
		puts(mins);
		puts(ans);
	}
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值