UVA-1590 IP Netwoks IP网络

题目

  • 详细题目
  • 题目分析
    • 由所给的一组IP地址得出这组IP地址的最小网络地址和子网掩码。
    • 子网掩码
      • 由1和0组成,1对应网络位,0对应主机位。
      • 假设0的个数为m,则2^m为这个子网对应的网络个数。但可用的IP地址数为2^m-2。因为全1和全0有特殊用处,不能作为使用。
  • 最小网络号
    • 同一子网的一组网络号的最小网络号其后几位为0,0的个数和子网掩码0的个数相同。

思路

  • 首先用ans[1005][4]存储这组IP地址
  • 按列进行比较,找到第一个不同的列,记录列的索引。
  • 对这列进行分析,由于存储的是十进制,所以应将其转化为二进制对每一位进行比较。从最低位开始比较,找出最后一个不同的位,记录其位置。
  • 根据之前记录的最高位不同的位置,计算最小网络号和子网掩码。
  • (最小网络号)这一位之前都和第一个IP地址的这列的二进制位相同,这一位及其之后的位都为0.并将其转化为十进制。
  • (子网掩码)这一位之前都为1,这一位及其之后都为0.并将其转化为十进制。
  • 根据记录的列的位置,输出最小网络号和子网掩码。

实现

#include<stdio.h> 
const int co = 1 << 7 ;//128
int ans[1005][4]; //输入1-1000个 

int main(){
	int m, t, k;
	while(scanf("%d",&m) != EOF){
		int i,j;
		for(i = 0; i < m; i++){
			scanf("%d.%d.%d.%d",&ans[i][0],&ans[i][1],&ans[i][2],&ans[i][3]);
		}
		//找到从哪一列开始不同 
		for(i = 0; i < 4; i++){	//将IP地址分为4部分,每部分一列 
			t = ans[0][i];	//标记第一个IP地址的各个部分的值
			int ok = 1;
			k = i;	//标记哪一个部分;
			for(j = 1; j < m; j++){
				if (ans[j][i] != t){	//按列比较IP地址的值 
					ok = 0;
					break;	//如果和第一个标记的不同,则退出 
				}
			}
			if(!ok)  break;	//如果找到一个不同的,则退出 
		}
		int s = 1;
		int p = 8;  	//将不一样的部分转化为8个二进制数,记录从第几个二进制开始不一样 
		for(i = 7; i >= 0; i--){
			t = (ans[0][k] / s) & 1;  //将ans[0][k]转化为2进制 ,从最低位开始(最右边)。 
			for ( j = 1; j < m; j++){
				if(((ans[j][k] / s) & 1) != t) p=i; //p记录 从左到右数第几个不一样的索引下标 
			}
			s = s * 2;  //和上边的ans[0][k]/s 合作完成二进制串的遍历 
		}
		
		int number = 0;//ip地址 
		int count = 0;//子网掩码地址 
		s = 1;
		for(i = 0; i < p; i++){	//ans[0][k]*s相当于每次循环扩大二倍,其二进制末尾加0 
			if ((ans[0][k] * s) & co) //通过移动二进制的位数,比较每位二进制是一还是0 128=1000 0000 
				number += 1<<(7-i);		//如果不为0,则将此位二进制转化为十进制 
		count += 1 << (7-i); 
		s = s * 2; 
		}
		
		if (k == 3) {
			printf("%d.%d.%d.%d\n",ans[0][0], ans[0][1], ans[0][2], number);
			printf("255.255.255.%d\n", count);
		}else if (k == 2)
         {
            printf("%d.%d.%d.0\n", ans[0][0], ans[0][1], number);
            printf("255.255.%d.0\n", count);
         }
         else if (k == 1)
         {
             printf("%d.%d.0.0\n", ans[0][0], number);
             printf("255.%d.0.0\n", count);
         }
         else
         {
             printf("%d.0.0.0\n", number);
             printf("%d.0.0.0\n", count);
         }
	}
} 

注意

  1. scanf("%d.%d.%d.%d",&ans[i][0],&ans[i][1],&ans[i][2],&ans[i][3]); 接收的格式
  2. s = 1;     for循环中  t = (ans[0][k] / s) & 1;       s = s * 2;
    • & 按位进行与运算,都1才1,否则为0.
    • t取得ans[0][k]的二进制的每一位。如ans[0][k] = 178 其二进制1011 0010
    • i = 0时 1011 0010 & 0000 0001 = 0000 0000 --->0
    • i = 1时 101 1001 & 000 0001 = 000 0001 --->1
    • i = 2时 10 1100 & 00 0001 = 00 0000 --->0
    • .......
    • i = 6时 10 & 01 = 00 ---> 0
    • i = 7时 1&1 = 1 ---> 1
    • 从下到上,即10110010 类似手算十进制转换为二进制。
  3. x / 2 相当于x的二进制向右移一位 x /4 相当于x的二进制向右移两位 (比如上边ans[0][k] / s)
  4. x * 2相当于x的二进制向左移一位,右边补一个0.
  5.    s=1        (ans[0][k] * s) & 128      s=s *2;   和2思想是一样的。
     作用区别

    t=(ans[0][k] / s) & 1

    t被赋予的顺序是从低位到高位
    t=(ans[0][k] * s) & 128(2^8)t被赋予的顺序是从高位到低位
     
    • 例子ans[0][k]=178     t=(ans[0][k] / s) & 1时,t=0,t=1,t=0,t=0,t=1,t=1,t=0,t=1

       二进制1011 0010      t=(ans[0][k] * s) & 128 时,t=1,t=0,t=1,t=1,t=0,t=0,t=1,t=0。两者正好相反
  6. if ((ans[0][k] * s) & 128)   number += 1<<(7-i);  
    • 1为true,0为false. 如果循环8次,则number=ans[0][k];如果循环5次,则number=2^7+2^5+2^4=176

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值