本系列文章我将总结我在刷算法题所用到的知识,如果你也在刷算法并且是新手,我相信这系列文章会很适合你。

【洛谷刷题 | 第十天】
-
- 今日题目:
-
- [1. [CSP-J 2021] 网络连接(模拟,字符串,枚举)](#1. [CSP-J 2021] 网络连接(模拟,字符串,枚举))
-
- [知识点:sscanf ,sprintf](#知识点:sscanf ,sprintf)
- [2. [CSP-J 2023] 公路(模拟,贪心,前缀和,反悔贪心)](#2. [CSP-J 2023] 公路(模拟,贪心,前缀和,反悔贪心))
今日题目:
1. [CSP-J 2021] 网络连接(模拟,字符串,枚举)
按顺序处理n(n≤1000)台计算机,每台为Server或Client并附带地址串,需验证地址是否符合a.b.c.d:e格式、a/b/c/d为0-255、e为0-65535且所有数字均无前导0;Server合法地址不可重复,重复输出FAIL,非法输出ERR,合法唯一输出OK;Client地址非法输出ERR,合法但无对应Server输出FAIL,合法且有对应Server输出其编号。
案例:
cpp
输入 输出
5 OK
Server 192.168.1.1:8080 FAIL
Server 192.168.1.1:8080 1
Client 192.168.1.1:8080 FAIL
Client 192.168.1.1:80 ERR
Client 192.168.1.1:99999
首先用map记录已成功建立连接的服务机地址与编号,核心编写地址校验函数:先用sscanf按a.b.c.d:e格式提取 5 个数字,提取失败直接判定非法,再检查数字是否在合法范围(a-d:0-255,e:0-65535),最后用sprintf重新拼接标准地址并与原地址逐字符对比,判断是否存在前导零等非法格式;逐台处理计算机,服务机地址非法输出 ERR,地址已存在输出 FAIL,合法唯一则记录地址并输出 OK,客户机地址非法输出 ERR,能找到对应服务机输出其编号,否则输出 FAIL。
题解:
cpp
#include<bits/stdc++.h>
using namespace std;
map<string,int> mp ;
bool ser(char s1[])
{
int a = -1,b=-1,c=-1,d=-1,e=-1;
int t = sscanf(s1,"%d.%d.%d.%d:%d",&a,&b,&c,&d,&e);
if(t!=5)
{
return 0;
}
if(a<0||a>255) return 0;
if(b<0||b>255) return 0;
if(c<0||c>255) return 0;
if(d<0||d>255) return 0;
if(e<0||e>65535) return 0;
char s2[25];
sprintf(s2,"%d.%d.%d.%d:%d",a,b,c,d,e);
int len1 = strlen(s1);
bool ok =1;
for(int i=0;i<len1;i++)
{
if(s1[i]!=s2[i])
{
ok = 0;
break;
}
}
return ok;
}
int main()
{
int n;
cin>>n;
string op;
char s[109];
for(int i=0;i<n;i++)
{
cin>>op>>s;
if(op=="Server")
{
if(!ser(s)) cout<<"ERR"<<'\n';
else if(mp.count(s))
cout<<"FAIL"<<'\n';
else{
mp[s] = i+1; cout << "OK\n";
}
}
if(op=="Client")
{
if(!ser(s)) cout<<"ERR"<<'\n';
else if(mp.count(s)) cout<<mp[s]<<'\n';
else cout<<"FAIL"<<'\n';
}
}
}
知识点:sscanf ,sprintf
sscanf ,sprintf在【洛谷刷题 | 第八天】已经介绍过,这里做一下小补充。
sscanf
cpp
sscanf(s1,"%d.%d.%d.%d:%d",&a,&b,&c,&d,&e);
一次性提取 5 个整数,存入 a、b、c、d、e
返回值 t 的作用:
t == 5 → 成功提取 5 个数,格式合法
t != 5 → 格式错误(少点、少冒号、多符号等)
sprintf
cpp
sprintf(s2,"%d.%d.%d.%d:%d",a,b,c,d,e);
把 a、b、c、d、e 按标准格式拼成地址存入 s2,
再和原地址 s1 逐字符比较,不一样就说明有前导零,非法。
sscanf 读取数字时,会自动忽略前导 0
sprintf 写入数字时,也不会自动加前导 0
2. [CSP-J 2023] 公路(模拟,贪心,前缀和,反悔贪心)
从站点 1 开到站点 n,相邻站点距离为 vᵢ,每站油价不同,油箱无限大,每升油能跑 d 公里,初始没油,在每个站只能加整数升油,求走完全程的最少花费。输入的第一行包含两个正整数 n 和 d;输入第二行包含 n-1 个正整数 v₁, v₂ ... vₙ₋₁,分别表示相邻两个站点之间的距离;输入第三行包含 n 个正整数 a₁, a₂ ... aₙ,分别表示每个站点出售汽油的单价。
案例:
cpp
输入 输出
5 4 79
10 10 10 10
9 8 9 6 5
采用贪心算法,从起点开始始终选择当前走过的最便宜油价加油,依次行驶到每个站点,累加需要行驶的总路程,每次用向上取整算出需要加的油量,乘以当前最低油价计入总花费,同时扣除已消耗的油量,持续到终点,最终得到最小油费。
题解:
cpp
#include<bits/stdc++.h>
using namespace std;
int a[100009];
int b[100009];
long long ans = 0;
int sum = 0;
int main()
{
int n,d;
cin>>n>>d;
for(int i=0;i<n-1;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++)
{
cin>>b[i];
}
int c= b[0];
int t=0;
for(int i=0;i<n-1;i++)
{
sum+=a[i];
c= min(c,b[i]);
if(sum>0){
ans+=(sum+d-1)/d*c;
sum-=(sum+d-1)/d*d;
}
}
cout<<ans;
}
最后:
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!
