UVA1590题解
sunyizhe
·
2023-09-10 20:27:20
·
题解
一、题面简洁翻译
有 n 个 IP 地址,现给出 n 和 n 个 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;
}
```