UVA1590题解

· · 题解

一、题面简洁翻译

n 个 IP 地址,现给出 nn 个 IP,求最小网络的网络地址和子网掩码。

二、思路

2.1 前置知识和基本思路

下文均以样例举例。

2.1.1 化成 32 位二进制数

首先,我们要知道什么是网络地址和子网掩码(子网掩码和翻译中的网络掩码是一个东西)(选读)。那么已经知道 n 个 IP 地址,如何算出最小网络的网络地址和子网掩码呢?很简单。首先,我们将所有的 IP 地址化成 32 位二进制数。化的方法很简单:只需要把用点号隔开的四个数分别化成二进制数,再按序拼起来即可。

样例化完以后是这样的(为了方便阅读,我把每个字节中间用空格隔开,实际操作不需要):

  194  .   85  .  160   . 177
11000010 01010101 10100000 10110001

  194  .   85  .  160   . 183
11000010 01010101 10101010 10110111

  194  .   85  .  160   . 178
11000010 01010101 10101010 10110010

2.1.2 计算子网掩码

接着开始算子网掩码。计算方法是这样的:看这 n 个二进制数,如果所有数的这一位都相同,那么这一位就是 1,否则当前位和后面位全都是 0。比如样例:

  194  .   85  .  160   . 177
11000010 01010101 10100000 10110001

  194  .   85  .  160   . 183
11000010 01010101 10101010 10110111

  194  .   85  .  160   . 178
11000010 01010101 10101010 10110010

11111111 11111111 11111111 11111000 => 255.255.255.248

其中,由于这三个数的倒数第三位并不完全相同,所以后面都是 0

2.1.2 计算网络地址

网络地址理解起来就更简单了:在 n 个 IP 中任挑一个与子网掩码进行按位与运算,得到的就是网络地址。依旧放样例:

  194  .   85  .  160   . 177
11000010 01010101 10100000 10110001

  255  .  255   . 255   . 248
11111111 11111111 11111111 11111000

11000010 01010101 10100000 10110000 => 网络地址:194.85.160.176

2.2 代码实现

我们用字符串模拟实现。我们需要如下函数:

整数转 8 位二进制数:

string IntTo8Bin(int x)
{
    string s="";
    if(x==0)s="0";
    while(x)
    {
        char ch=x%2+'0';
        s=ch+s;
        x/=2;
    }

    while(s.size()<8)s='0'+s;//补前导0变成8位数

    return s;
}

二进制数转整数:

string BinToInt(string s)//不要手残,循环里ans不要打成s
{
    string ans="";
    int x=(s[0]-'0')*128+(s[1]-'0')*64+(s[2]-'0')*32+(s[3]-'0')*16+(s[4]-'0')*8+(s[5]-'0')*4+(s[6]-'0')*2+(s[7]-'0');//暴力拼接
    if(x==0)return "0";
    while(x)
    {
        char ch=x%10+'0';
        ans=ch+ans;
        x/=10;
    }
    return ans;
}

IP 地址转 32 位二进制数:

string IpToBin(int a,int b,int c,int d)//a.b.c.d -> 32位二进制数
{
    string s=""+IntTo8Bin(a)+IntTo8Bin(b)+IntTo8Bin(c)+IntTo8Bin(d);
    return s;
}
```cpp string BinToIp(string s)//32位二进制数->4个1字节十进制数 { string a=s.substr(0,8),b=s.substr(8,8),c=s.substr(16,8),d=s.substr(24,8); string ans=""; ans=BinToInt(a)+"."+BinToInt(b)+"."+BinToInt(c)+"."+BinToInt(d);//暴力拼接 return ans; } ``` ## 三、代码 ```cpp //程序算法:模拟,计算机知识 #include <bits/stdc++.h> #define int unsigned using namespace std; const int N=1e3+10; string IP[N],ans1="",ans2="";//ans1:网络地址 ans2:网络掩码 void fast_read() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); } string IntTo8Bin(int x) { string s=""; if(x==0)s="0"; while(x) { char ch=x%2+'0'; s=ch+s; x/=2; } while(s.size()<8)s='0'+s; return s; } string BinToInt(string s)//不要手残,循环里ans不要打成s { string ans=""; int x=(s[0]-'0')*128+(s[1]-'0')*64+(s[2]-'0')*32+(s[3]-'0')*16+(s[4]-'0')*8+(s[5]-'0')*4+(s[6]-'0')*2+(s[7]-'0'); if(x==0)return "0"; while(x) { char ch=x%10+'0'; ans=ch+ans; x/=10; } return ans; } string IpToBin(int a,int b,int c,int d)//a.b.c.d -> 32位二进制数 { string s=""+IntTo8Bin(a)+IntTo8Bin(b)+IntTo8Bin(c)+IntTo8Bin(d); return s; } string BinToIp(string s)//32位二进制数->4个1字节十进制数 { string a=s.substr(0,8),b=s.substr(8,8),c=s.substr(16,8),d=s.substr(24,8); string ans=""; ans=BinToInt(a)+"."+BinToInt(b)+"."+BinToInt(c)+"."+BinToInt(d); return ans; } signed main() { //freopen("input.in","r",stdin); //freopen("output.out","w",stdout); int n; while(cin>>n) { ans1=ans2="";//多测不清空,爆0两行泪 for(int i=1;i<=n;i++) { int a,b,c,d; scanf("%d.%d.%d.%d",&a,&b,&c,&d); IP[i]=IpToBin(a,b,c,d); } //计算子网掩码 if(n==1)ans2="11111111111111111111111111111111";//特判,不然会越界访问,导致RE else { for(int i=0;i<32;i++) { bool flag=true; for(int j=2;j<=n;j++) if(IP[j][i]!=IP[j-1][i]) { flag=false; break; } if(flag)ans2+='1'; else { for(int j=i;j<32;j++)ans2+='0'; break; } } } //网络地址 string s=IP[1]; for(int i=0;i<32;i++)ans1+=(ans2[i]=='1'&&s[i]=='1')+'0';//手动与运算 cout<<BinToIp(ans1)<<endl; cout<<BinToIp(ans2)<<endl; } return 0; } ```