题意:
子网掩码是子网划分的依据,它跟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;
}