PAT刷题笔记
1003 Emergency
算法思路
单源最短路Dijkstra,需要维护点权和的最大值以及最短路的个数
注意:需要加强点权和的最大值以及最短路的个数的维护操作
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 510, M = 2 * N, INF = 0x3f3f3f3f;
int h[N], e[M], d[M], ne[M], idx;
int save[N], dist[N],sum[N],cnt[N];
bool st[N];
int n, m, src, dst;
int ans,Max;
void add(int a, int b, int c)
{
e[idx] = b;
d[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void Dijkstra()
{
memset(dist, INF, sizeof dist);
dist[src] = 0;
cnt[src] = 1;//初始时起点的最短路个数为1
sum[src] = save[src];//初始时起点的点权和(救援数量之和)为该点的点权
for (int i = 0; i < n; i++)
{
int Minj = -1;
for (int j = 0; j < n; j++)
{
if (!st[j] && (Minj == -1 || dist[j] < dist[Minj])) //注意,必要条件是该点未加入集合
{
Minj = j;
}
}
st[Minj] = 1;
for (int j = h[Minj]; j != -1; j = ne[j])
{
int b = e[j], dis = d[j];
if (st[b]) continue;//注意,若该点已加入集合则无需维护
if (dist[Minj] + dis < dist[b]) //找到更短的距离
{
dist[b] = dist[Minj] + dis;
cnt[b] = cnt[Minj];//最短路沿着该点走,该点的最短路个数更新为上一个点的个数
sum[b] = sum[Minj] + save[b];//最短路沿着该点走,该点的点权之和为上一个点权和加上该点的点权
}
else if (dist[Minj] + dis == dist[b]) //距离相等
{
cnt[b] += cnt[Minj];//注意:该点的最短路径个数加上上一个点的最短路个数
sum[b] = max(sum[b], sum[Minj] + save[b]);//该点的点权之和为各个路径点权和的最大值
}
}
}
printf("%d %d", cnt[dst], sum[dst]);
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d%d%d%d", &n, &m, &src, &dst);
for (int i = 0; i < n; i++)
{
scanf("%d", &save[i]);
}
while (m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
Dijkstra();
return 0;
}
1012 The Best Rank
注意要点
- 对成绩排序时从大到小,成绩相同时按照id升序排序
- 处理排名时不能只是单独排序后的下标,而是需要处理并列的排名,如1、1、3、4、5,而不是1、1、2、3、4,否则会有一个测试点不过
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2010, INF = 0x3f3f3f3f;
const string str = "ACME";
vector<pair<int, string>>v_C,v_M,v_E;
vector < pair<double, string>>v_A;
struct student {
int rank[4];
};
unordered_map<string, struct student>mp;
int n, m;
bool cmp1(const pair<int, string>& a, const pair<int, string>& b)
{
if (a.first != b.first) return a.first > b.first;
else return a.second < b.second;
}
bool cmp2(const pair<double, string>& a, const pair<double, string>& b)
{
if (a.first != b.first) return a.first > b.first;
else return a.second < b.second;
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++)
{
string id;
int C, M, E;
double A;
cin >> id >> C >> M >> E;
A = 1.0*(C + M + E) / 3;
v_C.push_back({ C,id });
v_M.push_back({ M,id });
v_E.push_back({ E,id });
v_A.push_back({ A,id });
}
sort(v_C.begin(),v_C.end(),cmp1);
sort(v_M.begin(), v_M.end(), cmp1);
sort(v_E.begin(), v_E.end(), cmp1);
sort(v_A.begin(), v_A.end(), cmp2);
double last1 = -1.0;
for (int i = 0; i < v_A.size(); i++)
{
if (v_A[i].first == last1) mp[v_A[i].second].rank[0] = mp[v_A[i - 1].second].rank[0];
else mp[v_A[i].second].rank[0] = i + 1;
last1 = v_A[i].first;
}
int last2 = -1;
for (int i = 0; i < v_C.size(); i++)
{
if (v_C[i].first == last2) mp[v_C[i].second].rank[1] = mp[v_C[i - 1].second].rank[1];
else mp[v_C[i].second].rank[1] = i + 1;
last2 = v_C[i].first;
}
last2 = -1;
for (int i = 0; i < v_M.size(); i++)
{
if (v_M[i].first == last2) mp[v_M[i].second].rank[2] = mp[v_M[i - 1].second].rank[2];
else mp[v_M[i].second].rank[2] = i + 1;
last2 = v_M[i].first;
}
last2 = -1;
for (int i = 0; i < v_E.size(); i++)
{
if (v_E[i].first == last1) mp[v_E[i].second].rank[3] = mp[v_E[i - 1].second].rank[3];
else mp[v_E[i].second].rank[3] = i + 1;
last2 = v_E[i].first;
}
while (m--)
{
string id;
cin >> id;
int min_k = 0;
if (mp.count(id))
{
for (int k = 0; k < 4; k++)
{
if (mp[id].rank[k] < mp[id].rank[min_k]) min_k = k;
}
cout << mp[id].rank[min_k] << ' ' << str[min_k] << endl;
}
else cout << "N/A" << endl;
}
return 0;
}
1013 Battle Over Cities
注意要点
- 用二维数组g来表示图和路径,其中0代表连通,1代表不连通,这样使用prim算法求得的最小生成树才是符合题意的路径个数
- 摧毁某个点在prim中的操作为
st[point] = true
,同时令该点的路权为1,i循环次数为n-1次,此时prim就会忽略这个点
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e3 + 10, INF = 0x3f3f3f3f;
int g[N][N],backup[N][N],dist[N];
int n, m, k;
bool st[N];
int prim(int except)
{
int res = 0;
memset(st, 0, sizeof st);
st[except] = true;
memset(dist, INF, sizeof dist);
for (int i = 0; i < n ; i++)
{
int Minj = -1;
for (int j = 1; j <= n; j++)
{
if (!st[j] && (Minj == -1 || dist[j] < dist[Minj]))
{
Minj = j;
}
}
if (i > 0) res += dist[Minj];
st[Minj] = true;
for (int j = 1; j <= n; j++)
{
dist[j] = min(dist[j], g[Minj][j]);
}
}
return res;
}
int query(int q)
{
memcpy(backup, g, sizeof g);
for (int i = 1; i <= n; i++)
{
g[i][q] = g[q][i] = 1;
}
int res = prim(q);
memcpy(g, backup, sizeof backup);
return res;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (i == j) g[i][j] = 0;
else g[i][j] = 1;
}
}
while (m--)
{
int a, b;
scanf("%d%d", &a, &b);
g[a][b] = g[b][a] = 0;
}
while (k--)
{
int q;
scanf("%d", &q);
printf("%d\n", query(q));
}
return 0;
}
1014 Waiting in Line
注意要点
- 维护每个队列的队头时间和队尾时间,队头时间用于选择最短的队列,队尾时间用于计算每个顾客得到服务的时间
- 先处理前n * m个顾客,按行优先加入队列;之后的顾客则选择最短的队列
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 25, M = 11, K = 1010, INF = 0x3f3f3f3f;
int n, m, k, q;
queue<int>line[N];//N个队列,存放每个顾客的处理时间
int front_time[N];//每个队列的队头时间,用于后k - n*m个顾客选择最短的队伍
int back_time[N];//每个队列的队尾时间,用于计算每个顾客服务完的时间
int c_time[K];//每个顾客的处理时间
int ans[K];
bool st[K];//是否超过下午5点
int main()
{
scanf("%d%d%d%d", &n, &m, &k, &q);
for (int i = 1; i <= k; i++)
{
scanf("%d", &c_time[i]);
}
//先处理前n*m个顾客,按行优先加入队列
int cur = 1;
for (int i = 1; i <= m; i++) //先枚举每个行
{
for (int j = 1; j <= n; j++) //再枚举每个队列
{
if (cur > n*m || cur > k) break;//超出n*m或人数不足时结束
line[j].push(c_time[cur]);
if (back_time[j] >= 540) st[cur] = 1;//接待时超过了17点
back_time[j] += c_time[cur];//维护队列队尾时间
ans[cur] = back_time[j];//维护答案
++cur;
if (i == 1) front_time[j] = back_time[j];//维护每个队列队头时间
}
}
//后处理n*m - k个顾客
while (cur <= k)
{
//每次先找到最短的队列
int Mini = 1;
for (int i = 2; i <= n; i++)
{
if (front_time[i] < front_time[Mini]) Mini = i;
}
line[Mini].pop();//先出队
front_time[Mini] += line[Mini].front();//维护队头时间
line[Mini].push(c_time[cur]);//队尾加入当前顾客
if (back_time[Mini] >= 540) st[cur] = 1;
back_time[Mini] += c_time[cur];//维护队列队尾时间
ans[cur] = back_time[Mini];//更新答案
++cur;
}
while (q--)
{
int x;
scanf("%d", &x);
if (st[x]) puts("Sorry");
else printf("%02d:%02d\n", ans[x] / 60 + 8, ans[x] % 60);
}
return 0;
}
1016 Phone Bills
注意要点
- 时间和金额的计算参考循环计时法
- scanf和cin可以连续使用
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, double> PID;
const int N = 1010, INF = 0x3f3f3f3f;
int n;
int price[24];
struct Date {
int month, dd, hh, mm;
bool operator<(const struct Date &t)
{
if (month != t.month) return month < t.month;
else if (dd != t.dd) return dd < t.dd;
else if (hh != t.hh) return hh < t.hh;
else return mm < t.mm;
}
bool operator!=(const struct Date& t)
{
return month != t.month || dd != t.dd || hh != t.hh || mm != t.mm;
}
void print()
{
printf("%02d:%02d:%02d ", this->dd, this->hh, this->mm);
}
};
struct record {
string name;
Date date;
bool st;//online:1 offline:0
bool operator<(const struct record& t)
{
if (name != t.name) return name < t.name;
else if (date != t.date) return date < t.date;
else return st < t.st;
}
};
record re[N];
struct bill {
string name;
Date date_from,date_to;
PID charge()
{
int cost = 0, time = 0;
int dd = date_from.dd, hh = date_from.hh,mm = date_from.mm;
while(dd <= date_to.dd)
{
while (hh < 24)
{
while (mm < 60)
{
if (dd == date_to.dd && hh == date_to.hh && mm == date_to.mm) return { time,1.0 * cost / 100 };
cost += price[hh];
time++;
++mm;
}
mm = 0;
++hh;
}
hh = 0;
dd++;
}
return { time,cost / 100.0 };
}
};
vector<bill>bills;
unordered_map<string, bool>mp;
unordered_map<string, Date>online;
int main()
{
for (int i = 0; i < 24; i++)
{
cin >> price[i];
}
cin >> n;
for(int i = 0;i < n;i++)
{
string name,state;
int month, dd, hh, mm;
bool st;
cin >> name;
scanf("%d:%d:%d:%d", &month, &dd, &hh, &mm);
cin >> state;
if (state == "on-line") st = 1;
else st = 0;
re[i] = {name,month,dd,hh,mm,st};
}
sort(re, re + n);
for (int i = 0; i < n; i++)
{
if (re[i].st == 1)
{
online[re[i].name] = re[i].date;
mp[re[i].name] = 1;
}
else
{
if (mp[re[i].name] == 1)
{
bills.push_back({ re[i].name,online[re[i].name],re[i].date });
}
mp[re[i].name] = 0;
}
}
for (int i = 0; i < bills.size(); i++)
{
cout << bills[i].name << ' ';
printf("%02d\n", bills[i].date_from.month);
int j;
double total = 0.0;
for ( j = i; j < bills.size() && bills[j].name == bills[i].name && bills[j].date_from.month == bills[i].date_from.month; j++)
{
bills[j].date_from.print();
bills[j].date_to.print();
PID tmp = bills[j].charge();
printf("%d $%.2lf\n", tmp.first, tmp.second);
total += tmp.second;
}
printf("Total amount: $%.2lf\n", total);
i = j - 1;
}
return 0;
}
1018 Public Bike Management Dijkstra + DFS
注意要点
- 首先,遇到最短路径,肯定是Dijstra,但题目说了,可能会有多条最短路径,我们要找到全部路径怎么办?把每一个路径都保存下来吗?可以,但没必要。我们只需要记录最短路径上每个节点的直接前驱就可以了,而这个,在Dijstra算法中,只需要在更新过程中(prev[v].push_back(u)),非常简单。如果它有多个最短路径,那么它就有多个直接前驱,因此,每个节点都应该有一个vector来保存它的全部最短路径的直接前驱,最终,就是需要一个vector数组。
- 找到最短路径显然是不够的,我们还要进行选择,选择PCBC按哪一条路走,需要带过去的自行车最少。所以,我们要遍历全部最短路径,于是dfs就出场了,因为我们保存的是它的直接前驱,所以需要从sp往PCBC去遍历。对于每一个最短路径,模拟一次PCBC需要进行的调整过程(逐个访问节点,并根据它的当前容量计算它达到完美需要的自行车参数),记录需要带过来或带回去的自行车数目,如果更少,则选择这条路径。
- 有一个好的技巧是,我们的完美状态是cmax/2,刚开始给出了所有站点的当前容量,但我们不直接保存它的当前容量,我们用diff数组保存每个站点当前容量与完美状态的差值,这样,我们很容易根据这个值的正负知道它是缺少自行车,缺少几个?或者是需要自行车,需要几个?
- 所以,总的来说就是,Dijstra找到全部最短路径,dfs遍历每个最短路径并找到最好的那个,选择路径的原则就是,距离最短>距离相同但发送的自行车最少>距离相同发送的自行车也相同但带回的自行车最少。
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, double> PID;
const int N = 1010, INF = 0x3f3f3f3f;
int n;
int price[24];
struct Date {
int month, dd, hh, mm;
bool operator<(const struct Date &t)
{
if (month != t.month) return month < t.month;
else if (dd != t.dd) return dd < t.dd;
else if (hh != t.hh) return hh < t.hh;
else return mm < t.mm;
}
bool operator!=(const struct Date& t)
{
return month != t.month || dd != t.dd || hh != t.hh || mm != t.mm;
}
void print()
{
printf("%02d:%02d:%02d ", this->dd, this->hh, this->mm);
}
};
struct record {
string name;
Date date;
bool st;//online:1 offline:0
bool operator<(const struct record& t)
{
if (name != t.name) return name < t.name;
else if (date != t.date) return date < t.date;
else return st < t.st;
}
};
record re[N];
struct bill {
string name;
Date date_from,date_to;
PID charge()
{
int cost = 0, time = 0;
int dd = date_from.dd, hh = date_from.hh,mm = date_from.mm;
while(dd <= date_to.dd)
{
while (hh < 24)
{
while (mm < 60)
{
if (dd == date_to.dd && hh == date_to.hh && mm == date_to.mm) return { time,1.0 * cost / 100 };
cost += price[hh];
time++;
++mm;
}
mm = 0;
++hh;
}
hh = 0;
dd++;
}
return { time,cost / 100.0 };
}
};
vector<bill>bills;
unordered_map<string, bool>mp;
unordered_map<string, Date>online;
int main()
{
for (int i = 0; i < 24; i++)
{
cin >> price[i];
}
cin >> n;
for(int i = 0;i < n;i++)
{
string name,state;
int month, dd, hh, mm;
bool st;
cin >> name;
scanf("%d:%d:%d:%d", &month, &dd, &hh, &mm);
cin >> state;
if (state == "on-line") st = 1;
else st = 0;
re[i] = {name,month,dd,hh,mm,st};
}
sort(re, re + n);
for (int i = 0; i < n; i++)
{
if (re[i].st == 1)
{
online[re[i].name] = re[i].date;
mp[re[i].name] = 1;
}
else
{
if (mp[re[i].name] == 1)
{
bills.push_back({ re[i].name,online[re[i].name],re[i].date });
}
mp[re[i].name] = 0;
}
}
for (int i = 0; i < bills.size(); i++)
{
cout << bills[i].name << ' ';
printf("%02d\n", bills[i].date_from.month);
int j;
double total = 0.0;
for ( j = i; j < bills.size() && bills[j].name == bills[i].name && bills[j].date_from.month == bills[i].date_from.month; j++)
{
bills[j].date_from.print();
bills[j].date_to.print();
PID tmp = bills[j].charge();
printf("%d $%.2lf\n", tmp.first, tmp.second);
total += tmp.second;
}
printf("Total amount: $%.2lf\n", total);
i = j - 1;
}
return 0;
}
1017 Queueing at Bank 大模拟:多窗口排队
注意要点
- 处理每个顾客受理时间要考虑到顾客到来时刻和窗口运行时刻,不能只考虑窗口运行时刻,否则在处理顾客到来时刻比窗口时间晚时出错
- 更新窗口时刻应该为当前顾客受理时刻+处理时间
代码
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e4 + 10, K = 105,INF = 0x3f3f3f3f;
int n, k;
queue<int>q;
int window_time[K];//每个窗口当前的运行时间
struct User {
int come_time, process_time,end_time;
bool operator<(const struct User& t)
{
return come_time < t.come_time;
}
};
User users[N];
int cnt;
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++)
{
int hh, mm, ss, process_time;
scanf("%d:%d:%d %d", &hh, &mm, &ss, &process_time);
if (hh * 3600 + mm * 60 + ss > 17 * 3600) continue;
users[cnt++] = {hh * 3600 + mm * 60 + ss,process_time*60,0};
}
sort(users, users+cnt);//按时间先后对用户排序(排队操作)
for (int i = 0; i < cnt; i++)//将每个用户入队
{
q.push(i);
}
//初始化每个窗口的当前服务时间为08:00
for (int i = 0; i < k; i++)
{
window_time[i] = 8 * 3600;
}
//出队并处理
while (!q.empty())
{
//每次选择最快(时间最短)的窗口
int Mini = 0;
for (int i = 1; i < k; i++)
{
if (window_time[i] < window_time[Mini]) Mini = i;
}
int num = q.front(); q.pop();//队头顾客出队并受理
//注意:此处顾客受理时间要考虑到顾客到来时刻和窗口运行时刻,不能只考虑窗口运行时刻,否则在处理顾客到来时刻比窗口时间晚时出错
users[num].end_time = max(window_time[Mini],users[num].come_time);
//注意:更新窗口时刻应该为当前顾客受理时刻+处理时间
window_time[Mini] = users[num].end_time + users[num].process_time;
}
//计算答案:处理时刻 - 到来时刻
LL sum = 0;
for (int i = 0; i < cnt; i++)
{
sum += users[i].end_time - users[i].come_time;
}
printf("%.1lf\n", (double)sum / cnt / 60);
return 0;
}
优化方法
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e4 + 10, K = 105,INF = 0x3f3f3f3f;
int n, k;
priority_queue<int, vector<int>, greater<int>>heap;//每个窗口当前的运行时间
struct User {
int come_time, process_time,end_time;
bool operator<(const struct User& t)
{
return come_time < t.come_time;
}
};
User users[N];
int cnt;
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++)
{
int hh, mm, ss, process_time;
scanf("%d:%d:%d %d", &hh, &mm, &ss, &process_time);
if (hh * 3600 + mm * 60 + ss > 17 * 3600) continue;
users[cnt++] = {hh * 3600 + mm * 60 + ss,process_time*60,0};
}
sort(users, users+cnt);//按时间先后对用户排序(排队操作)
//初始化每个窗口的当前服务时间为08:00
for (int i = 0; i < k; i++)
{
heap.push(8 * 3600);
}
//出队并处理
for(int k = 0;k < cnt;k++)
{
//每次选择最快(时间最短)的窗口
int window_time = heap.top(); heap.pop();
//队头顾客出队并受理
//注意:此处顾客受理时间要考虑到顾客到来时刻和窗口运行时刻,不能只考虑窗口运行时刻,否则在处理顾客到来时刻比窗口时间晚时出错
users[k].end_time = max(window_time,users[k].come_time);
//注意:更新窗口时刻应该为当前顾客受理时刻+处理时间
heap.push(users[k].end_time + users[k].process_time);
}
//计算答案:处理时刻 - 到来时刻
LL sum = 0;
for (int i = 0; i < cnt; i++)
{
sum += users[i].end_time - users[i].come_time;
}
printf("%.1lf\n", (double)sum / cnt / 60);
return 0;
}
1032 Sharing 找出两个链表的公共结点
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
unordered_map<int, char>val;
unordered_map<int, int>nxt;
int headA, headB, n;
int main()
{
scanf("%d%d%d", &headA, &headB, &n);
for (int i = 0; i < n; i++)
{
int add, next;
char c;
scanf("%d %c %d", &add, &c, &next);
val[add] = c;
nxt[add] = next;
}
int cur1 = headA, cur2 = headB;
//l1:a + c l2:b + c cur1:a + c + b + c cur2: b + c + a + c
//a + c + b = b + c + a 故两个指针一定会在c的开头相遇,即公共部分的首节点
while (cur1 != cur2)
{
cur1 = (cur1 == -1 ? headB : nxt[cur1]);
cur2 = (cur2 == -1 ? headA : nxt[cur2]);
}
if (cur1 != -1) printf("%05d", cur1);
else printf("-1");
return 0;
}
1038 Recover the Smallest Number 字符串拼接获得最小值
思路
其实就是一个序的关系,所有的组合有n!种,(像"所谓组出最小数其实是获得字典序最小的拼接方式"这种废话我就不说了)。假设我们获得了其中的一个组合,然后又两个相邻的数字片段a,b。然后我们就要想,把a和b交换能不能使整个序列变小呢?这个问题的其实等价于b+a 是否小于a+b(此处"+"为连接符),也就是说对于这样一个序列,如果某两个相邻的元素之间发生交换可以使得整个序列的值变小,我们就应该坚决的交换啊,所以这里定义一个新的序,用<<来表示,若a+b < b + a 则a应当在b前面,即a << b。然后呢,这种序是满足传递性的若a<<b ,b << c,则a<<c,所以迭代到最后,我们就会获得一个任何两个相邻元素都不能交换的局面,也就是所谓的答案。
这样一来我们的算法就有了,比较每两个相邻的元素,如果交换可以使得整个序列变大,就交换之,直到最后没有任何两个值之间能进行交换,啊,这不就是传说中的Bubble_Sort吗,真是一个令人激动的结论啊。对序列按照之前定义的序进行排序,如此就好了。
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
bool cmp(string& a, string& b) //保证按照能够组成的最小数字的形式排列,牢记这种写法
{
return a + b < b + a;
}
vector<string>v;
int n;
string ans;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
string str;
cin >> str;
v.push_back(str);
}
sort(v.begin(), v.end(), cmp);
for (int i = 0; i < v.size(); i++)
{
ans += v[i];
}
//去除前导零
reverse(ans.begin(), ans.end());
while (ans.back() == '0' && ans.size() > 1) ans.pop_back();
reverse(ans.begin(), ans.end());
cout << ans << endl;
return 0;
}
1043 Is It a Binary Search Tree 二叉树新颖考法
思路
- 由于题目只给出了先序数字序列,并未给出结构,所以只能使用二叉搜索树插入的方法来构建二叉树
- 接着先序遍历这棵树,若与输入序列相同,则说明是二叉树
- 由于给出的序列可能是镜像二叉树,所以还需要按照“根右左”的方式遍历构造的树,若与输入序列相同,则说明是镜像二叉树
- 根据类型后续遍历这棵树即可
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e3 + 10, INF = 0x3f3f3f3f;
struct TreeNode {
int val;
struct TreeNode* left, * right;
TreeNode(int x)
{
val = x;
left = right = NULL;
}
};
int n;
vector<int>seq,res;
bool is_mirror;
TreeNode* insert(TreeNode *cur,int x)
{
if (!cur)
{
cur = new TreeNode(x);
return cur;
}
if (x < cur->val)
{
cur->left = insert(cur->left, x);
}
else cur->right = insert(cur->right, x);
return cur;
}
void pre_order(TreeNode* root, vector<int>& v)
{
if (root)
{
v.push_back(root->val);
pre_order(root->left, v);
pre_order(root->right, v);
}
return;
}
void mirror_pre_order(TreeNode* root, vector<int>& v)
{
if (root)
{
v.push_back(root->val);
mirror_pre_order(root->right, v);
mirror_pre_order(root->left, v);
}
return;
}
void post_order(TreeNode* root)
{
if (root)
{
if (is_mirror)
{
if (root->right) post_order(root->right);
if (root->left) post_order(root->left);
}
else
{
if (root->left) post_order(root->left);
if (root->right) post_order(root->right);
}
res.push_back(root->val);
}
}
int main()
{
scanf("%d", &n);
TreeNode* root = NULL;
for (int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
seq.push_back(x);
root = insert(root, x);
}
vector<int>seq1,seq2;
pre_order(root, seq1);
mirror_pre_order(root, seq2);
if (seq1 == seq)
{
puts("YES");
}
else if (seq2 == seq)
{
puts("YES");
is_mirror = true;
}
else
{
puts("NO");
return 0;
}
post_order(root);
for (int i = 0; i < res.size(); i++)
{
printf("%d", res[i]);
if (i != res.size() - 1) printf(" ");
}
return 0;
}
1051 Pop Sequence 判断出栈顺序是否合理 模拟题 已掌握
思路
- 用栈容器模拟即可
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<unordered_set>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e3 + 10, INF = 0x3f3f3f3f;
int n, m, k;
int Max;//当前出栈的最大值
int seq[N];//输入序列
int main()
{
scanf("%d%d%d", &m, &n, &k);
while (k--)
{
bool f = 1;
Max = 0;
stack<int>stk;
//以上为初始化环节
for (int i = 0; i < n; i++)
{
scanf("%d", &seq[i]);
}
for (int i = 0; i < n; i++)
{
if (stk.empty() || seq[i] > stk.top()) //栈空或者当前出栈值大于栈顶值,说明需要入栈
{
for (int j = Max + 1; j <= seq[i]; j++) //入栈从出栈最大值+1开始,因为出栈最大值之前的元素都已入栈,避免重复入栈
{
stk.push(j);
}
if (stk.size() > m) //栈中元素个数超过规定容量
{
f = 0;
break;
}
Max = max(Max, stk.top());
stk.pop();
}
else if (seq[i] == stk.top()) //当前出栈值等于栈顶值,直接出栈
{
Max = max(Max, stk.top());
stk.pop();
}
else //当前出栈值小于栈顶值,不符合常理
{
f = 0;
break;
}
}
if (f) puts("YES");
else puts("NO");
}
return 0;
}
1060 Are They Equal 科学计数法 各种不合法输入,情况复杂
思路
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
string a, b;
int n;
string normalize(string& str,int &n)
{
if (atof(str.c_str()) == 0.0) //0.000 00.000
{
string res = "0.";
for (int i = 0; i < n; i++)
{
res += '0';
}
res += "*10^0";
return res;
}
while (str[0] == '0' && str[1] != '.') //05.00 -> 5.00
{
str.erase(0, 1);
}
if (str[0] == '0') //0.xxx
{
int sub = 0;
while (1)
{
int pos = str.find('.');
if (str[pos + 1] == '0')
{
str.erase(pos + 1, 1);
sub++;
}
else break;
}
while (str.size() > n + 2) str.pop_back();
while (str.size() < n + 2) str += '0';
str += "*10^";
str += to_string(-sub);
return str;
}
else //5.xxx 567.8
{
int dot = str.find('.');
if (dot == string::npos)
{
dot = str.size();
}
string res = "0.";
for (char c : str)
{
if (c != '.') res += c;
}
while (res.size() > n + 2) res.pop_back();
while (res.size() < n + 2) res += '0';
res += "*10^";
res += to_string(dot);
return res;
}
}
int main()
{
scanf("%d", &n);
cin >> a >> b;
if (n == 0)
{
cout << "YES 0" << endl;
}
string std_a = normalize(a, n), std_b = normalize(b, n);
if (std_a == std_b)
{
cout << "YES " << std_a << endl;
}
else
{
cout << "NO " << std_a << ' ' << std_b << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)