今天写的第一个题,题目描述看起来并不男,这个也确实很容易想,一开始直接用结构体存储数据,然后每次创建新的结构体数组保存每次查询的人进行 自定义cmp结构体排序,很容易实现,第一次跑出了唯一一个超时没有出来,其他还是可以的。
代码如下:
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
struct Person {
string name;
int age;
int worth;
};
bool cmp(Person&A, Person&B) {
return A.worth == B.worth ? (A.age == B.age ? (A.name<B.name) : A.age < B.age) : A.worth >B.worth;
}
int main() {
int N, M, age1, num, age2;
scanf("%d %d", &N, &M);
vector<Person>V;
Person tmp;
for (int i = 0; i < N; i++) {
cin.ignore();
cin >> tmp.name >> tmp.age >> tmp.worth;
V.push_back(tmp);
}
for (int i = 0; i < M; i++) {
scanf("%d %d %d", &num, &age1, &age2);
vector<Person>V2;
for (int i = 0; i < V.size(); i++) {
if (V[i].age >= age1 && V[i].age <= age2)V2.push_back(V[i]);
}
sort(V2.begin(), V2.end(), cmp);
printf("Case #%d:\n", i + 1);
if (V2.size() == 0) {
printf("None\n"); continue;
}
for (int j = 0; j < min(num, (int)V2.size()); j++) printf("%s %d %d\n", V2[j].name.c_str(), V2[j].age, V2[j].worth);
}
return 0;
}
但是很显然有一个超时,有一个差点超时,肯定不能就这么放了他。
于是我想到,是不是每次库函数sort排序太费时间了?
很自然我想到了把库函数删掉,改用直接存取的堆进行处理,于是出现了set版本的二次代码,不过这里我遇到了一个小问题,因为我是在原函数的基础上修改的,所以下图出现了一个问题
如果要查询的数量num大于Set的数量还好说,不会出错,问题是如果S的数量太,因为S不能像数组一样访问下标,所以每次只能这样取元素,导致每次循环j都会改变循环条件,解决方法就是在外面用一个变量直接取第一次set的大小,就可以修正了。
二次代码如下:
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
struct Person {
string name;
int age;
int worth;
};
bool operator<(const Person&A, const Person&B) {
return A.worth == B.worth ? (A.age == B.age ? (A.name<B.name) : A.age < B.age) : A.worth >B.worth;
}
int main() {
int N, M, age1, num, age2;
scanf("%d %d", &N, &M);
vector<Person>V;
Person tmp;
for (int i = 0; i < N; i++) {
cin.ignore();
cin >> tmp.name;
scanf("%d %d", &tmp.age, &tmp.worth);
V.push_back(tmp);
}
for (int i = 0; i < M; i++) {
scanf("%d %d %d", &num, &age1, &age2);
set<Person>S;
for (int i = 0; i < V.size(); i++) {
if (V[i].age >= age1 && V[i].age <= age2)
S.insert(V[i]);
}
printf("Case #%d:\n", i + 1);
if (S.size() == 0) {
printf("None\n"); continue;
}
int m = S.size();
for (int j = 0; j <min(num, m); j++) {
printf("%s %d %d\n", S.begin()->name.c_str(), S.begin()->age, S.begin()->worth);
S.erase(S.begin());
}
}
return 0;
}
很显然优秀了一丢丢,因为第1个测试点已经减少了50ms处理时间,但是对第二个还是没法救回来。
于是乎,把仅存的一个cin>>string改成char数组,可是我一开始忘记了修改cmp里面的函数,导致出错了几个测试的,我一度怀疑自己是不是用错了c预言的string,终于吃了个饭回来一眼就看到了这个错误。
经过修改:
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
#include<string.h>
using namespace std;
struct Person {
char name[10];
int age;
int worth;
};
bool operator<(const Person&A, const Person&B) {
return A.worth == B.worth ? (A.age == B.age ? (strcmp(A.name,B.name)<0?true:false) : A.age < B.age) : A.worth >B.worth;
}
int main() {
int N, M, age1, num, age2;
scanf("%d %d", &N, &M);
vector<Person>V;
Person tmp;
for (int i = 0; i < N; i++) {
cin.ignore();
scanf("%s", tmp.name);
scanf("%d %d", &tmp.age, &tmp.worth);
V.push_back(tmp);
}
for (int i = 0; i < M; i++) {
scanf("%d %d %d", &num, &age1, &age2);
set<Person>S;
for (int i = 0; i < V.size(); i++) {
if (V[i].age >= age1 && V[i].age <= age2)
S.insert(V[i]);
}
printf("Case #%d:\n", i + 1);
if (S.size() == 0) {
printf("None\n"); continue;
}
int m = S.size();
for (int j = 0; j <min(num, m); j++) {
printf("%s %d %d\n",S.begin()->name,S.begin()->age, S.begin()->worth);
S.erase(S.begin());
}
}
return 0;
}
好吧,还是需要对输入进行处理了,不能每次都线型找表。
经过简单修改,还是超时!
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<set>
#include<string.h>
using namespace std;
struct Person {
char name[10];
int age;
int worth;
};
bool operator<(const Person&A, const Person&B) {
return A.worth == B.worth ? (A.age == B.age ? (strcmp(A.name,B.name)<0?true:false) : A.age < B.age) : A.worth >B.worth;
}
int main() {
int N, M, age1, num, age2;
scanf("%d %d", &N, &M);
vector<vector<Person> >V(201);
Person tmp;
for (int i = 0; i < N; i++) {
cin.ignore();
scanf("%s", tmp.name);
scanf("%d %d", &tmp.age, &tmp.worth);
V[tmp.age].push_back(tmp);
}
for (int i = 0; i < M; i++) {
scanf("%d %d %d", &num, &age1, &age2);
set<Person>S;
for (int i = age1; i <=age2; i++) {
for (int j = 0; j < V[i].size(); j++)S.insert(V[i][j]);
}
printf("Case #%d:\n", i + 1);
if (S.size() == 0) {
printf("None\n"); continue;
}
int m = S.size();
for (int j = 0; j <min(num, m); j++) {
printf("%s %d %d\n",S.begin()->name,S.begin()->age, S.begin()->worth);
S.erase(S.begin());
}
}
return 0;
}
额,可是我已经把第1个优化到40ms的水平了,还是应付不了第2个,再次优化!
经过我仔细分析,很显然查询语句最多103次,而人的数据最多105次,我猜他肯定是直接取年龄范围0-200,这样就导致每次都是108数量级以上的次数,肯定会超时。
参考了晴神的书,这个题写了蛮久的,当然拿大半分还是很简单的,但是做人嘛,不追求完美那多没意思。
AC代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
struct Person {
char name[10];
int age, worth;
};
bool cmp(Person&A, Person&B) {
return A.worth == B.worth ? (A.age == B.age ? (strcmp(A.name, B.name) < 0 ? true : false) : (A.age < B.age)) : A.worth > B.worth;
}
vector<Person>V(100010);
vector<Person>Y(100010);
int P[201] = { 0 };
int main() {
int N, M, age1, age2, num, ym = 0;
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++) {
scanf("%s %d %d", &V[i].name, &V[i].age, &V[i].worth);
}
sort(V.begin(), V.begin()+N, cmp);
for (int i = 0; i < N; i++) {
if (P[V[i].age] < 100) {
P[V[i].age]++;
Y[ym++] = V[i];
}
}
for (int j = 0; j < M; j++) {
scanf("%d %d %d", &num, &age1, &age2);
int printm = 0;
printf("Case #%d:\n", j + 1);
for (int i = 0; i < ym&&printm < num; i++) {
if (Y[i].age >= age1 && Y[i].age <= age2) {
printf("%s %d %d\n", Y[i].name, Y[i].age, Y[i].worth);
printm++;
}
}
if (printm==0)printf("None\n");
}
return 0;
}
通过这个题我还是学到了很多东西,首先:
大容量的数组最好写在函数外面,因为写在函数里的变量能申请的空间很小,写在外面可以很大。
第二个就是,要进行预处理,就是减少循环里面的运算,而是尽量写到循环外面,不然一个103次方的循环里,随便一点运算复杂度都会增加三个数量级复杂度。但是写到循环外面就可以做到和循环并列复杂度,n+n远小于nn
还有一个地方就是注意分清楚每个变量的意思,不然一个地方写的不合适,也许会骗过很多测试点,但是总有那种大数据的测试点过不了。