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

链接

注意要点

  1. 对成绩排序时从大到小,成绩相同时按照id升序排序
  2. 处理排名时不能只是单独排序后的下标,而是需要处理并列的排名,如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

链接

注意要点

  1. 用二维数组g来表示图和路径,其中0代表连通,1代表不连通,这样使用prim算法求得的最小生成树才是符合题意的路径个数
  2. 摧毁某个点在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

链接

注意要点

  1. 维护每个队列的队头时间和队尾时间,队头时间用于选择最短的队列,队尾时间用于计算每个顾客得到服务的时间
  2. 先处理前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

链接

注意要点

  1. 时间和金额的计算参考循环计时法
  2. 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

链接

注意要点

  1. 首先,遇到最短路径,肯定是Dijstra,但题目说了,可能会有多条最短路径,我们要找到全部路径怎么办?把每一个路径都保存下来吗?可以,但没必要。我们只需要记录最短路径上每个节点的直接前驱就可以了,而这个,在Dijstra算法中,只需要在更新过程中(prev[v].push_back(u)),非常简单。如果它有多个最短路径,那么它就有多个直接前驱,因此,每个节点都应该有一个vector来保存它的全部最短路径的直接前驱,最终,就是需要一个vector数组。
  2. 找到最短路径显然是不够的,我们还要进行选择,选择PCBC按哪一条路走,需要带过去的自行车最少。所以,我们要遍历全部最短路径,于是dfs就出场了,因为我们保存的是它的直接前驱,所以需要从sp往PCBC去遍历。对于每一个最短路径,模拟一次PCBC需要进行的调整过程(逐个访问节点,并根据它的当前容量计算它达到完美需要的自行车参数),记录需要带过来或带回去的自行车数目,如果更少,则选择这条路径。
  3. 有一个好的技巧是,我们的完美状态是cmax/2,刚开始给出了所有站点的当前容量,但我们不直接保存它的当前容量,我们用diff数组保存每个站点当前容量与完美状态的差值,这样,我们很容易根据这个值的正负知道它是缺少自行车,缺少几个?或者是需要自行车,需要几个?
  4. 所以,总的来说就是,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 大模拟:多窗口排队

链接

注意要点

  1. 处理每个顾客受理时间要考虑到顾客到来时刻和窗口运行时刻,不能只考虑窗口运行时刻,否则在处理顾客到来时刻比窗口时间晚时出错
  2. 更新窗口时刻应该为当前顾客受理时刻+处理时间

代码

#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 找出两个链表的公共结点

链接
复习时务必参考力扣LCR.023

#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 二叉树新颖考法

链接

思路

  1. 由于题目只给出了先序数字序列,并未给出结构,所以只能使用二叉搜索树插入的方法来构建二叉树
  2. 接着先序遍历这棵树,若与输入序列相同,则说明是二叉树
  3. 由于给出的序列可能是镜像二叉树,所以还需要按照“根右左”的方式遍历构造的树,若与输入序列相同,则说明是镜像二叉树
  4. 根据类型后续遍历这棵树即可
#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 判断出栈顺序是否合理 模拟题 已掌握

链接

思路

  1. 用栈容器模拟即可
#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;
}
posted @   安河桥北i  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示