UVA - 1590 IP Networks

来源:Online Judge

题目大意:

给定一组 ip 地址,求一个能够包含这组 ip 的子网。

比较繁琐的办法就是模拟。ip 地址可以用4个十进制数表示,对于每个十进制数,如果所有的 ip 地址中的该为都相等,说明它们已经处在同一个网络下。只有当某个十位数不等时,说明该位是应该改变的网络号。

#include<algorithm>
#include <iostream>
#include  <cstdlib>
#include  <cstring>
#include   <string>
#include   <vector>
#include   <cstdio>
#include    <queue>
#include    <stack>
#include    <ctime>
#include    <cmath>
#include      <map>
#include      <set>
#define ll long long
#define INF 0x3f3f3f3f
#define db1(x) cout<<#x<<"="<<(x)<<endl
#define db2(x,y) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<endl
#define db3(x,y,z) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<endl
#define db4(x,y,z,a) cout<<#x<<"="<<(x)<<", "<<#y<<"="<<(y)<<", "<<#z<<"="<<(z)<<", "<<#a<<"="<<(a)<<endl
#define NUMBER_OF_THREADS   10
using namespace std;

int pow_2[8]={128,64,32,16,8,4,2,1};

int main(int argc,char *argv[])
{
    #ifdef test
    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    clock_t start=clock();
    #endif //test

    int n;
    while(~scanf("%d",&n))
    {
        int ipadress[1010][4]={0};
        char s[20];
        for(int i=0;i<n;++i)
        {
            scanf("%s",s);
            int temp=0,t=0;
            for(int j=0;s[j]!='\0';++j)
            {
                if(s[j]!='.')temp=temp*10+(s[j]-'0');
                else ipadress[i][t]=temp,temp=0,t++;
            }
            ipadress[i][t]=temp,temp=0,t++;
        }

        int f;
        int mask[4]={0},anss[4]={0},num[260]={0},cnt[1010]={0};
        for(f=0;f<4;++f)//总共4个十进制数,从第1个开始查找不同
        {
            int t=0;
            for(int j=0;j<256;++j)num[j]=0;//用一个数组存储出现的十进制数次数
            for(int j=0;j<n;++j)
                num[ipadress[j][f]]++;
            for(int j=0;j<256;++j)
                if(num[j])cnt[t++]=j;
            if(t==1)mask[f]=255,anss[f]=cnt[0];//如果只出现了一个数,则进入下一个
            else//出现了多个十进制数,说明该位是需要修改的网络号
            {
                int x=9,y=ipadress[0][f];//找到最长相同的二进制前缀
                int binip[10]={0};//将第一个IP地址的该位转为二进制
                for(int l=0;l<8;++l)
                    if(y>=pow_2[l])binip[l]=1,y-=pow_2[l];
                for(int k=0;k<n;++k)//对所有的ip地址进行转化
                {
                    int ans=ipadress[k][f];
                    for(int l=0;l<8;++l)
                    {
                        if(ans>=pow_2[l]&&binip[l]==0)
                        {
                            x=min(x,l);break;
                        }
                        else if(ans<pow_2[l]&&binip[l]==1)
                        {
                            x=min(x,l);break;
                        }
                        if(ans>=pow_2[l])ans-=pow_2[l];
                    }
                }

                int ans=255;
                for(int k=7;k>=x;--k)
                    ans-=pow_2[k];
                mask[f]=ans;
                for(int l=0;l<x;++l)
                    anss[f]+=pow_2[l]*binip[l];

                break;
            }
        }
        for(int i=0;i<4;++i)
            if(!i)printf("%d",anss[i]);
            else printf(".%d",anss[i]);
        printf("\n");
        for(int i=0;i<4;++i)
            if(!i)printf("%d",mask[i]);
            else printf(".%d",mask[i]);
        printf("\n");
    }

    #ifdef test
    clock_t end=clock();
    double endtime=(double)(end-start)/CLOCKS_PER_SEC;
    printf("\n\n\n\n\n");
    cout<<"Total time:"<<endtime<<"s"<<endl;        //s为单位
    cout<<"Total time:"<<endtime*1000<<"ms"<<endl;    //ms为单位
    #endif //test
    return 0;
}

一个更好的方法是用位运算。

#include <stdio.h>
#include <string.h>
const int MAXN = 1e3+5;
int mask[4],arr_ip[MAXN][4],ip[4];
int arr_mask[9]={255,254,252,248,240,224,192,128,0};

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(mask,0,sizeof(mask));
        memset(ip,0,sizeof(ip));
        for(int i=0;i<n;i++)
            scanf("%d.%d.%d.%d",&arr_ip[i][0],&arr_ip[i][1],&arr_ip[i][2],&arr_ip[i][3]);
        for(int i=0;i<4;i++)
        {
            int mi=0x3f3f3f3f,mx=0;
            for(int j=0;j<n;j++)//遍历所有ip地址的第i个十进制数
            {
                if(mi>arr_ip[j][i]) mi=arr_ip[j][i];//第i位上最小的十进制数
                if(mx<arr_ip[j][i]) mx=arr_ip[j][i];//第i位上最大的十进制数
            }
            int x=mx^mi,ix;//对mi与mx进行异或运算。x=0说明mi=mx
            for(int j=0;j<=8;j++)
                if(!(x>>j)) { ix=j; break;}//对x进行移位运算,可直接求出最长前缀位数
            mask[i]=arr_mask[ix];
            if(mask[i]!=255) break;
        }
        for(int i=0;i<4;i++)
            ip[i]=arr_ip[0][i]&mask[i];
        printf("%d.%d.%d.%d\n",ip[0],ip[1],ip[2],ip[3]);
        printf("%d.%d.%d.%d\n",mask[0],mask[1],mask[2],mask[3]);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值