由一次算法笔试引起的反思 c++特定格式读取 自定义比较函数 输出保留小数位数

某个题目:
 
若干任务。每个任务完成有一定时间。每个任务有上游任务,必须先完成上游任务才能去做该任务。可以同时进行最多n个任务。
输入格式为一行字符串:
h:[e,f,g]:2;e:[b]:6;f:[c]:6;g:[d]:6;b:[a]:5;c:[a]:5;d:[a]:5;a:[]:3/2

 

斜杠后的数字表示最多同时进行的任务数量。

分号隔开若干个任务描述。
每个任务描述组成方式:name:[name2,name3,name4,…]:time
中括号内为上游任务。
求完成这一系列任务需要的最小总时间(例程答案为22)
 
 
对于python而言直接使用split即可。
c++就不太方便了。现在的一个做法是转换成istringstream然后用getline
 
如:
void Split(const string s, vector<string>& output, const char ch) {
    istringstream ss(s);
    string tmp;
    while(getline(ss, tmp, ch)) {
        if (tmp == "") continue;
        output.push_back(tmp);
    }
}
sstream 还可以用来做格式转换(字符串与整型浮点型布尔型的转换)
 
template<class T>
void to_string(string & result,const T& t) {
    ostringstream oss;//创建一个流
    oss<<t;//把值传递如流中
    result=oss.str();//获取转换后的字符转并将其写入result
}
不过c++11以后的自带的to_string函数已经很强大了。不需要自己定义了。
 
template<class out_type,class in_value>
out_type convert(const in_value & t){
    stringstream stream;
    stream<<t;//向流中传值
    out_type result;//这里存储转换结果
    stream>>result;//向result中写入值
    return result;
}

注意iss oss的区别,前者只能是 iss>>xxxx, 后者只能是oss << xxxx。而ss两个方向都可以。

 
某个题目二:
 
有很多人。分为ABC三级。
每个C级人属于唯一一个B级人,每个B级人属于唯一一个A级人。
每个C级人有一个分数。B级人的分数等于其管理的全部C级人分数之和,
A级人的分数等于其管理的全部B级人分数之和。
输入内容:
 
value
Jacky,23
Lily,42
Cindy,87
Tomy,2

organization
Jone,Cris,Jacky
Jone,Troy,Lily
Ben,Andy,Cindy
Ben,Tim,Tomy
eof
解释:value说明了每个C级人的分数。organizatoin说明了从属关系,表示“A级,B级,C级”
希望输出内容为:
 
Ben<89>
-Andy<87>
--Cindy<87>
-Tim<2>
--Tomy<2>
Jone<65>
-Cris<23>
--Jacky<23>
-Troy<42>
--Lily<42>
先输出A级人,再输出其管理的B级人,加短横,再输出B级人管理的C级人,加两条短横。
每个人后用尖括号将分数包围着输出。
要按照得分降序排序。如果得分相同,则按照人名字母序升序排序。
 
【分析】需要自定义大小比较函数。
 
自定义比较函数。
比如sort函数传入的第三个参数即是自定义的比较函数。
https://blog.csdn.net/weixin_41588502/article/details/86620305
bool less_int(int a,int b){
        return a<b;
    }
sort(vec.begin(), vec.end(), less_int);
通常来说,排列时,从小到大就是less,即第一个小于第二个。升序。
第三个参数同时也可以是类里的仿函数:
struct cmp {
    bool operator() (const  Node & s1, const Node & s2)  {
        if(s1.x==s2.x) return s1.y<s2.y;
        else  return s1.x< s2.x;
    }
};
sort(a,a+n,cmp());

 

也可以重载小于符号,然后不写第三个参数。
 
bool operator< (const Node& s1, const Node& s2) {
    if(s1.x==s2.x)  return s1.y<s2.y;//年龄相同时,按姓名小到大排
    else  return s1.x> s2.x; //从年龄大到小排序
}
sort(a,a+n);

 

 
对于优先队列这样的容器而言,自定义比较函数也有三种方式:
仿函数写法:
#include<queue>
#include<vector>
#include<iostream>
using namespace std;
struct node
{
    int x, y;
    node(int x,int y):x(x),y(y){}
};
struct cmp
{
    bool operator()(node a,node b) // 其实是在重载()符号
    {
        if(a.x == b.x)  return a.y >= b.y;
        else return a.x > b.x;
    }
};
int main()
{
    priority_queue<node,vector<node>,cmp> pq;    //带有三个参数的优先队列;
    for(int i = 1; i <= 5; i++)
        for(int j = 1; j <= 5; j++)
            pq.push(node(i,j));
    while(!pq.empty())
    {
        cout<<pq.top().x<<" "<<pq.top().y<<endl;
        pq.pop();
    }
    return 0;
}

 

也可以重载小于符号
#include<queue>
#include<iostream>
using namespace std;
struct node
{
    int x, y;
    node(int x,int y):x(x),y(y){}
};
bool operator< (node a,node b)
{
    if(a.x == b.x)  return a.y >= b.y;
    else return a.x > b.x;
}
int main()
{
    priority_queue<node> pq;    //只传node,但是node结构体的<运算符已被改变
}

 

重载也可以写在结构体定义里面(此时必须用const)
struct node
{
      int x, y;
      node(int x, int y):x(x),y(y){}
      bool operator< (const node &b) const   //写在里面只用一个b,但是要用const和&修饰,并且外面还要const修饰;
      {
           if(x == b.x)  return y >= b.y;
           else return x > b.x;
      }
};

 

【总结】自定义比较函数建议全部采用结构体仿函数的形式。这样sort、容器都可以同时使用了。
 
再补充俩知识点:priority_queue对于“大小”的理解是反过来的!即使用<,但表示的是大顶堆!原因在于他是一个队列,队列的top其实是在数组最后面!即最大的在队列的顶部也就是这个数组的最后面。因此最前面的不一定是最小的(堆的性质)!
 
字符串按照字母序进行比较的函数:
逐位比较,越靠前则越大。
“abc" > "bbc" 
前面完全相同,字符串越长就越大。
"abcc"> "abc"
大写排在小写的后面(这和阿斯克码顺序一致)
"abc">"Abc" 
 
 
【其他】顺序容器与关联容器讲的不错的博客:
 
【输出保留小数位数】
#include <iomanip>
float a = 23.32323
cout<<setiosflags(ios::fixed)<<setprecision(2) << a;

// 或者直接输出
printf("%.2f", a);

 

补充:

如果采用python则:
 

import sys

for line in sys.stdin
    lines = line.split(',')

# 或者

while True:
    line = sys.stdin.readline()
    lines = line.split(',')
    if line == ''
        break

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值