PTA L2 题目合集

L2-001 紧急救援 (25 分)

题解链接

L2-002 链表去重 (25 分)

#include<bits/stdc++.h>
#define PIS pair <int, string>
#define val first
#define ne second
using namespace std;
const int N = 1e6+10;

map<string, PIS> Map;

string st_address;
int n, st[N];

vector <string> v;

int main()
{
	cin >> st_address >> n;
	for (int i = 0;i < n;i ++) {
		string ad, ne;
		int val;
		cin >> ad >> val >> ne;
		Map[ad] = {val, ne};
	}
	
	string p = st_address;
	while (p != "-1") {
		st[abs(Map[p].val)] = 1;
		string t = Map[p].ne;
		while (t != "-1") {
			if (st[abs(Map[t].val)]) 
				v.push_back (t);
			else 
				break;
			t = Map[t].ne;
		}
		Map[p].ne = t;
		cout << p << ' ' << Map[p].val << ' ' << Map[p].ne << endl;
		p = t;
	}
	int len = v.size()-1; // 不能直接用i < v.size()-1,段错误,不知道为什么 
	for (int i = 0;i < len;i ++)
	cout << v[i] << ' ' << Map[v[i]].val << ' ' << v[i+1] << endl;
	if (v.size() > 0) cout << v[v.size()-1] << ' ' << Map[v[v.size()-1]].val << ' ' << -1 << endl;
	return 0;
}

L2-004 这是二叉搜索树吗? (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1100;
int n, a[N];
vector <int> v;

void dfs (int l, int r, int mir) {
	if (l > r) return ;
	int rt = a[l];
	int p = l+1, q = l+1;
	if (!mir) { // 非镜像
		while (p <= r && a[p] < rt) p ++, q ++; // 找到第一个大于等于根节点的,也就是右子树的开头
		while (q <= r && a[q] >= rt) q ++; // 找到右子树的结尾的后一个
	} else {
		while (p <= r && a[p] >= rt) p ++, q ++;
		while (q <= r && a[q] < rt) q ++;
	}
	dfs (l+1, p-1, mir);
	dfs (p, q-1, mir);
	v.push_back (rt); // 直接按照后续遍历的顺序保存;先dfs左右子树后再将根节点加入v中;如果中序遍历,只需要改变push_back语句与dfs语句的次序即可
}

void print () {
	puts ("YES");
	cout << v[0];
	for (int i = 1;i < v.size();i ++)
		cout << ' ' << v[i];
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	
	dfs (1, n, 0);
	
	if (v.size () == n) { // 如果v中包含了n个元素,说明n个数全部加入
		print ();
		return 0;
	}
	
	v.clear ();
	dfs (1, n, 1);
	
	if (v.size() == n) print ();
	else puts ("NO");

	return 0;
}

L2-003 月饼 (25 分)

贪心而已,按照性价比排序。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n;
double D, ans = 0;

struct node {
	double a, b, c;	
} yb[N];

bool cmp (node a, node b) {
	return a.c > b.c;
}

int main()
{
	cin >> n >> D;
	for (int i = 0;i < n;i ++) cin >> yb[i].a;
	for (int i = 0;i < n;i ++) cin >> yb[i].b, yb[i].c = 1.0 * yb[i].b / yb[i].a;
	
	sort (yb, yb+n, cmp);
	
	for (int i = 0;i < n && D;i ++) {
		if (D >= yb[i].a) {
			D -= yb[i].a;
			ans += yb[i].b;
		} else {
			ans += D * yb[i].c;
			break;
		}
	}
	
	printf ("%.2f\n", ans); // 原来可以直接这样控制保留小数 // 这我都忘记了

	return 0;
}

L2-005 集合相似度 (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;

int n, m;
set <string> s[N];

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) {
		cin >> m;
		while (m --) {
			string str;
			cin >> str;
			s[i].insert (str);
		}
	}
	
	cin >> m;
	while (m --) {
		int a, b, nc = 0, nt = 0;
		cin >> a >> b;
		for (auto i : s[a]) 
			if (s[b].find (i) != s[b].end ()) 
				nc ++;
		nt = s[a].size () + s[b].size () - nc;
		printf ("%.2lf\%\n", 100.0 * nc / nt);
	}

	return 0;
}

L2-006 树的遍历 (25 分)

#include<bits/stdc++.h>
using namespace std;

vector <int> v;

int a[50], b[50], n, left_val[50], right_val[50];

int dfs (int l1, int r1, int l2, int r2) {
	
	if (l1 > r1 || l2 > r2) return 0;
	
	int root = a[r1], p = l2;	
	while (p <= r2) {
		if (b[p] == root) break;
		p ++;
	}
	int left_sum = p - l2;
	left_val[root] = dfs (l1, l1+left_sum-1, l2, p-1); // left_subtree
	right_val[root] = dfs (l1+left_sum, r1-1, p+1, r2); // right_subtree
	return root;
}

void bfs (int x) {
	queue <int> q;
	q.push (x);
	while (q.size ()) {
		int t = q.front ();
		q.pop ();
		v.push_back (t);
		if (left_val[t]) q.push (left_val[t]);
		if (right_val[t]) q.push (right_val[t]);
	}	
}

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	for (int i = 1;i <= n;i ++) cin >> b[i];
	
	dfs (1, n, 1, n);
	bfs (a[n]);
	
	cout << v[0];
	for (int i = 1;i < v.size();i ++)
	cout << ' ' << v[i];

	return 0;
}

L2-008 最长对称子串 (25 分)

一开始想二分判断,结果发现并不可行,比如:abba,长度为3的时候是不行的,但长度为4的时候是可行的。

#include<bits/stdc++.h>
using namespace std;
string s;
int main()
{
	getline (cin, s);
	for (int len = s.size();len > 0;len --) {
		for (int j = 0;j < s.size()-len+1;j ++) {
			string ss = s.substr (j, len);
			int l = 0, r = ss.size()-1;
			while (l < r) {
				if (ss[l] == ss[r]) l ++, r --;
				else break;
			}
			if (l >= r) {
				cout << len << endl;
				return 0;
			}
		}
	}		

	return 0;
}

L2-009 抢红包 (25 分)

#include<bits/stdc++.h>
using namespace std;

const int N = 1e4+10;

struct node {
	int id, num, money;
} info[N];

bool cmp (node a, node b) {
	if (a.money != b.money) return a.money > b.money;
	if (a.num != b.num) return a.num > b.num;
	return a.id < b.id;
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1;i <= n;i ++) {
		info[i].id = i; // ! // 样例中的编号6只发不收,如果没有这句话其id一直为0
		int k;
		cin >> k;
		while (k --) {
			int id, money;
			cin >> id >> money;
			info[id].id = id;
			info[id].num ++;
			info[id].money += money;
			info[i].money -= money;
		}
	}
	
	sort (info+1, info+n+1, cmp);
	
	for (int i = 1;i <= n;i ++) {
		printf ("%d %.2lf\n", info[i].id, info[i].money / 100.0);
	}

	return 0;
}

L2-010 排座位 (25 分)

并查集的用法。

#include<bits/stdc++.h>
using namespace std;
const int N = 110;

bool duili[N][N];
int fa[N];

int find (int x) {
	return x == fa[x] ? fa[x] : fa[x] = find (fa[x]);
}

void join (int x, int y) {
	int rx = find (x), ry = find (y);
	if (rx != ry) fa[rx] = ry;
}

int main()
{
	int n, m, k;
	int a, b, re;
	cin >> n >> m >> k;
	for (int i = 0;i <= 100;i ++) fa[i] = i;
	while (m -- ) {
		cin >> a >> b >> re;
		if (re == -1) 
			duili[a][b] = duili[b][a] = true;
		else 
			join (a, b);
	}	
	
	while (k -- ) {
		cin >> a >> b;
		int ra = find (a), rb = find (b);
		bool bool1 = (ra == rb), bool2 = duili[a][b];
		if (bool1 && !bool2) cout << "No problem" << endl;
		else if (!bool1 && !bool2) cout << "OK" << endl;
		else if (bool1 && bool2) cout << "OK but..." << endl;
		else cout << "No way" << endl;
	}	

	return 0;
}

L2-011 玩转二叉树 (25 分)

和上面的第六题几乎一样。

#include<bits/stdc++.h>
using namespace std;
const int N = 50;

int n, a[N], b[N];
int right_subtree_root[N<<1], left_subtree_root[N<<1];

int dfs (int l1, int r1, int l2, int r2) {
	if (l1 > r1 || l2 > r2) return 0;
	
	int rt = b[l2];
	int p = l1;
	while (p <= r1 && a[p] != rt) p ++;
	
	right_subtree_root[rt] = dfs (l1, p-1, l2+1, l2+p-l1); // 镜像,dfs左子树,但是赋值给rt的右子树数组 
	left_subtree_root[rt] = dfs (p+1, r1, l2+p-l1+1, r2); // 前序遍历数组左子树和右子树索引范围的判定,是根据中序遍历得到左子树元素个数和右子树元素个数 
	return rt;
}

void bfs (int x) {
	vector <int> v;
	queue <int> q;
	q.push (x);
	while (q.size()) {
		int t = q.front ();
		v.push_back (t);
		q.pop ();
		if (left_subtree_root[t]) q.push (left_subtree_root[t]); // 因为在dfs时已经进行过镜像操作了,所以这里就先左子树数组再右子树数组 
		if (right_subtree_root[t]) q.push (right_subtree_root[t]);
	}
	
	cout << v[0] ;
	for (int i = 1;i < v.size();i ++) cout << ' ' << v[i];
}

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i]; // mid
	for (int i = 1;i <= n;i ++) cin >> b[i]; // before
	
	dfs (1, n, 1, n);
	
	bfs (b[1]);
	
	return 0;
}

L2-012 关于堆的判断 (25 分)

首先要知道堆插入元素的更新原理;还要利用二叉树索引的特点。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;

int n, m, idx;
int tr[N];

int main()
{
	cin >> n >> m;
	for (int i = 1;i <= n;i ++) {
		int x;
		cin >> x;
		tr[++ idx] = x;
		int t = idx;
		while (t != 1) {
			if (tr[t>>1] > tr[t]) swap (tr[t>>1], tr[t]), t >>= 1;
			else break;
		}
	}	
	while (m --) {
		int a = 0, b = 0, op;
		cin >> a;
		string s;
		while (cin >> s) {
			if (s == "root") {
				op = 1;
				break;
			} else if (s == "and") {
				cin >> b >> s >> s;
				op = 2;
				break;
			} else if (s == "parent") {
				cin >> s >> b;
				op = 3;
				break;
			} else if (s == "child") {
				cin >> s >> b;
				op = 4;
				break;
			}
		}
		if (op == 1) {
			if (a == tr[1]) puts ("T");
			else puts ("F");
		} else {
			int idx_a = 0, idx_b = 0;
			for (int i = 1;i <= idx;i ++)
				if (tr[i] == a) idx_a = i;
				else if (tr[i] == b) idx_b = i;
			if (op == 2 && ((idx_a>>1) == (idx_b>>1))) puts ("T");
			else if (op == 3 && (idx_a == (idx_b>>1))) puts ("T");
			else if (op == 4 && (idx_b == (idx_a>>1))) puts ("T");
			else puts ("F");  
		}
	}

	return 0;
}

L2-013 红色警报 (25 分)

并查集。

每次删除一座城市就将其标记一下,每删除一座城市,就使用全部关系(除了被标记的城市)重新构件连通块,判断连通分支数是否比删除该城市前的连通分支数大,如果前者大说明改变了连通性。当连通分支数为0时,说明没有城市了,game over。

#include<bits/stdc++.h>
using namespace std;
const int N = 600, M = 5010;
int fa[N], st[N], a[M], b[M];

int find (int x) {
	return x == fa[x] ? fa[x] : fa[x] = find (fa[x]);
}

void join (int x, int y) {
	int rx = find (x), ry = find (y);
	if (rx != ry) fa[rx] = ry;
}

int main()
{
	int n, m, c, k, cnt_unit = 0, loss = 0;
	cin >> n >> m;
	for (int i = 0;i < n;i ++) fa[i] = i;
	for (int i = 0;i < m;i ++) {
		cin >> a[i] >> b[i];
		join (a[i], b[i]);
	}	
	cin >> k;
	
	for (int i = 0;i < n;i ++) 
		if (fa[i] == i) 
			cnt_unit ++;
	
	while (k -- ) {
		cin >> c;
		st[c] = 1;
		loss ++;
		for (int i = 0;i < n;i ++) fa[i] = i;
		for (int i = 0;i < m;i ++) 
			if (!st[a[i]] && !st[b[i]])
				join (a[i], b[i]);
		
		int cnt = 0;
		for (int i = 0;i < n;i ++) 
			if (!st[i] && fa[i] == i)
				cnt ++; 
		
		if (cnt > cnt_unit) printf ("Red Alert: City %d is lost!\n", c);
		else printf ("City %d is lost.\n", c);
		if (cnt == 0) cout << "Game Over." << endl;
		cnt_unit = cnt;
	}
	return 0;
}

L2-014 列车调度 (25 分)

本质是贪心。

但是这个题的贪心思路与计算最长上升子序列的贪心思路是一样的,所以直接使用最长上升子序列的优化模板。

模板

贪心思路讲解

还不理解可以看yxc的课程,有一节课讲过(不是这道题,而是贪心思路)(动态规划章节)。

#include<bits/stdc++.h>
using namespace std;
int n, ans, a[100010], d[100010], len;

int erfen (int x) {
	int l = 1, r = len, mid;
	while (l < r) {
		mid = l + r >> 1;
		if (d[mid] >= x) r = mid;
		else l = mid + 1;
	}	
	return l;
}

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	for (int i = 1;i <= n;i ++)	{
		if (a[i] > d[len]) d[++len] = a[i];
		else d[erfen (a[i])] = a[i]; // 等价于 d[lower_bound(d+1, d+len+1, a[i]) - d] = a[i]
	}
	cout << len << endl;

	return 0;
}

L2-015 互评成绩 (25 分)

太欣慰了,L2居然有签到!

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
vector <double> v;
int n, k, m;
int s[10010][20];

int main()
{
	cin >> n >> k >> m;
	for (int i = 1;i <= n;i ++) {
		int mx = 0;
		int mn = INF;
		int sum = 0;
		for (int j = 1;j <= k;j ++)	{
			cin >> s[i][j];
			mx = max (mx, s[i][j]);
			mn = min (mn, s[i][j]);
			sum += s[i][j];
		}
		v.push_back (1.0 * (sum - mx - mn) / (k - 2));
	}
	
	sort (v.begin(), v.end());
	
	printf ("%.3lf", v[v.size()-m]);
	for (int i = v.size()-m+1;i < v.size();i ++) 
		printf (" %.3lf", v[i]);
		
	return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹 (25 分)

题解链接

L2-017 人以群分 (25 分)

先保证人数最小差距,再保证和的最大差距。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int diff, l_num, r_num = N, a[N], b[N], sum;
int n;
int main () {
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> a[i], sum += a[i];
	sort (a + 1, a + n + 1);
	for (int i = 1;i <= n;i ++) {
		b[i] = b[i-1] + a[i];
		int r_sum = sum - b[i];
		int l_sum = b[i];
		int t_left = i, t_right = n - i;
		if (abs (t_right - t_left) < abs (l_num - r_num)) 
			l_num = t_left, r_num = t_right, diff = r_sum - l_sum;
		else if (abs (t_right - t_left) == abs (l_num - r_num)) {
			if (r_sum - l_sum > diff) {
				diff = r_sum - l_sum;
				l_num = i;
				r_num = n - i;
			}
		}
	}
	cout << "Outgoing #: " << r_num << endl;
	cout << "Introverted #: " << l_num << endl;
	cout << "Diff = " << diff << endl;
	
}

L2-019 悄悄关注 (25 分)

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;

int n, m, sum, cnt;
string name;
set <string> s;
vector <string> v;
map <string, int> click;

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) {
		cin >> name;
		s.insert (name);
	}
	cin >> m;
	for (int i = 1;i <= m;i ++) {
		cin >> name >> cnt;
		click.insert ({name, cnt});
		sum += cnt;
	}
	double avg = 1.0 * sum / m;
	for (auto item : click) {
		name = item.x;
		cnt = item.y;
		if (cnt > avg && s.find (name) == s.end ())
			v.push_back (name);
	}
	
	if (v.size () == 0) puts("Bing Mei You");
	else {
		sort (v.begin (), v.end ());
		for (auto i : v) cout << i << endl;
	}

	return 0;
}

L2-020 功夫传人 (25 分)

DFS。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int n;
int ddz[N];
double z, r, ans, bili;
int e[N<<1], ne[N<<1], h[N], idx;

void add (int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs (int x, double g) {
	if (ddz[x]) ans += g * ddz[x];
	for (int i = h[x];~i;i = ne[i]) {
		int j = e[i];
		dfs (j, g * bili);
	}
}


int main()
{
	memset (h, -1, sizeof h);
	cin >> n >> z >> r;
	for (int i = 0;i < n;i ++) {
		int k;
		cin >> k;
		if (k == 0) {
			cin >> ddz[i];
		} else {
			while (k --) {
				int u;
				cin >> u;
				add (i, u);
			}
		}
	}
	bili = (100.0 - r) / 100.0;
	dfs (0, z); // 祖师爷也可能是得道者 
	
	cout << int (ans) << endl;
	
	return 0;
}

L2-021 点赞狂魔 (25 分)

#include<bits/stdc++.h>
using namespace std;

set <int> s;

struct people {
	string name;
	int sum;
	int dif;
} peo[110];

bool cmp (people a, people b) {
	if (a.dif != b.dif) return a.dif > b.dif;
	return (1.0 * a.dif / a.sum) > (1.0 * b.dif / b.sum);
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1;i <= n;i ++) {
		cin >> peo[i].name >> peo[i].sum;
		s.clear ();
		for (int j = 1;j <= peo[i].sum;j ++) {
			int pass;
			cin >> pass;
			s.insert (pass);
		}
		peo[i].dif = s.size();
	}	
	
	sort (peo + 1, peo + n + 1, cmp);
	
	if (n == 0) cout << "- - -" << endl;
	else if (n == 1) cout << peo[1].name << " - -" << endl;
	else if (n == 2) cout << peo[1].name << ' ' << peo[2].name << " -" << endl;
	else cout << peo[1].name << ' ' << peo[2].name << ' ' << peo[3].name << endl;

	return 0;
}

L2-022 重排链表 (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

struct Node {
	int val, next, pre;
} node[N];

int start_address, n;

int main()
{
	cin >> start_address >> n;
	for (int i = 1;i <= n;i ++) {
		int a, b, c;
		cin >> a >> b >> c;
		node[a].val = b;
		node[a].next = c;
		node[c].pre = a;
	}
	
	int p = start_address, end_address = start_address, cnt = 0;
	while (p != -1) {
		end_address = p;
		p = node[p].next;
		cnt ++;
	}	
	n = cnt; // 更新n为链路上的节点数 
	
	for (int i = 1;i <= (n-1)/2;i ++) { // 仅执行前面若干步,到达边界的输出单独判断 
		// 先打印右边的 
		printf ("%05d %d %05d\n", end_address, node[end_address].val, start_address);
		end_address = node[end_address].pre;
		// 再打印左边的 
		printf ("%05d %d %05d\n", start_address, node[start_address].val, end_address);
		start_address = node[start_address].next;
	}
	
	if (n & 1) { // 最后一步是显示右边,记得输出-1 
		printf ("%05d %d -1\n", end_address, node[end_address].val);
	} else { // 先显示右边,再显示左边,记得输出-1 
		printf ("%05d %d %05d\n", end_address, node[end_address].val, start_address);
		printf ("%05d %d -1\n", start_address, node[start_address].val);
	}

	return 0;
}
/*
// n = cnt;
00100 3
00100 4 00000
00000 1 -1
68237 6 00000
*/

L2-023 图着色问题 (25 分)

注意三点:

  1. 判断相邻点是否同色,不用深搜、宽搜的,直接遍历每个点的临边即可;
  2. 上色颜色必须为k,大于小于都不行;
  3. 使用邻接表存边时,需要开数组到2e6,否则最后一个测试点死活过不去.
#include<bits/stdc++.h>
using namespace std;

const int N = 1000, M = 2e6+10;

vector<vector<int>> v(N);

int V, E, K, n;
int st[N], color[N];
int e[M], ne[M], h[N], idx;

void add (int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;	
}

bool check (int x) {
	for (int i = h[x];~i;i = ne[i]) {
		int j = e[i];
		if (color[j] == color[x]) return false;
	}
//	for(int j = 0; j < v[x].size(); j++)
//		if(color[x] == color[v[x][j]]) return false;
	return true;
}

int main()
{
	memset (h, -1, sizeof h);
	cin >> V >> E >> K;
	while (E --) {
		int a, b;
		cin >> a >> b;
		add (a, b);
		add (b, a);
//		v[a].push_back(b);
//		v[b].push_back(a);
	} 
	
	cin >> n;
	while (n --) {
		set <int> s;
		for (int i = 1;i <= V;i ++) 
			cin >> color[i], 
			s.insert (color[i]);
		if (s.size () != K) 
			puts ("No");
		else {
			int flag = 0;
			for (int i = 1;i <= V;i ++) {
				if (!check (i)) {
					flag = 1;
					break;
				}
			}
			
			if (flag) puts ("No");
			else puts ("Yes");
		}
	}

	return 0;
}

L2-024 部落 (25 分)

并查集。

每次用小圈子的第一个人与剩下的人join即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
int n, k, a, b, sum, dif;
int fa[N], st[N];

int find (int x) {
	return fa[x] == x ? fa[x] : fa[x] = find (fa[x]);
}

int main()
{
	cin >> n;
	for (int i = 0;i < N;i ++) fa[i] = i;
	while (n --) {
		cin >> k >> a;
		st[a] = 1;
		for (int i = 1;i < k;i ++) { // 除去第一个还剩k-1个
			cin >> b;
			st[b] = 1;
			int ra = find (a), rb = find (b);
			if (ra != rb) fa[ra] = rb;
		}
	}	
	
	for (int i = 1;i < N;i ++)
		if (st[i]) {
			sum ++;
			if (fa[i] == i) dif ++;
		} 
	cout << sum << ' ' << dif << endl;
	
	cin >> k;
	while (k --) {
		cin >> a >> b;
		int ra = find (a), rb = find (b);
		if (ra == rb) puts ("Y");
		else puts ("N");
	}

	return 0;
}

L2-025 分而治之 (25 分)

和前面的红色警报是一个原理。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;

int n, m;
int st[N], a[N], b[N], fa[N];

int find (int x) {
	return fa[x] == x ? fa[x] : fa[x] = find (fa[x]);
}

void join (int x, int y) {
	int rx = find (x), ry = find (y);
	if (rx != ry) fa[rx] = ry;
}

bool check () {
	for (int i = 1;i <= n;i ++)
		if (!st[i]) 
			if (fa[i] != i) 
				return false;
	return true;
}

int main()
{
	cin >> n >> m;
	for (int i = 1;i <= n;i ++) fa[i] = i;
	for (int i = 1;i <= m;i ++) {
		cin >> a[i] >> b[i];
		join (a[i], b[i]);
	}
	int k;
	cin >> k;
	while (k --) {
		memset (st, 0, sizeof st);
		int p;
		cin >> p;
		while (p --) {
			int city;
			cin >> city;
			st[city] = 1;
		}
		for (int i = 1;i <= n;i ++) fa[i] = i;
		for (int i = 1;i <= m;i ++) {
			int c1 = a[i], c2 = b[i];
			if (!st[c1] && !st[c2]) 
				join (c1, c2);
		}
		if (check ()) puts ("YES");
		else puts ("NO");
	}

	return 0;
}

L2-026 小字辈 (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n, rt, mx, dp[N];
int e[N<<1], ne[N<<1], h[N], idx; 

void add (int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void bfs (int x) {
	queue<int> q;
	q.push (x);
	dp[x] = 1;
	while (q.size ()) {
		int t = q.front ();
		q.pop ();
		mx = max (mx, dp[t]); // 放在for里面会少只有根节点的情况 
		for (int i = h[t];~i;i = ne[i]) {
			int j = e[i];
			if (!dp[j]) dp[j] = dp[t] + 1;
			q.push (j);
		}
	}
}

int main()
{
	cin >> n;
	memset (h, -1, sizeof h);
	for (int i = 1;i <= n;i ++)	 {
		int j;
		cin >> j;
		if (j != -1) add (j, i);
		else rt = i;
	}
	
	bfs (rt);

	cout << mx << endl;
	int i = 1;
	while (dp[i] != mx) i ++;
	cout << i;
	i ++;
	for (;i <= n;i ++) 
		if (dp[i] == mx)
			cout << ' ' << i; 
	return 0;
}

L2-027 名人堂与代金券 (25 分)

美观一点的话还可以使用pair。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;

int n, G, k, money, r[N];


struct student {
	string em;
	int sc;
} stu[N];

bool cmp (student a, student b) {
	if (a.sc != b.sc) return a.sc > b.sc;
	return a.em < b.em;
}

int main()
{
	cin >> n >> G >> k;
	for (int i = 1;i <= n;i ++) {
		cin >> stu[i].em >> stu[i].sc;
		if (stu[i].sc >= G) money += 50;
		else if (stu[i].sc >= 60) money += 20;
	}	

	sort (stu+1, stu+n+1, cmp);
	cout << money << endl;
	
	for (int i = 1;i <= n;i ++) {
		if (stu[i].sc != stu[i-1].sc) r[i] = i;
		else r[i] = r[i-1];
		if (r[i] <= k) 
			cout << r[i] << ' ' << stu[i].em << ' ' << stu[i].sc << endl;
	}
	
	return 0;
}

L2-028 秀恩爱分得快 (25 分)

坑太深:

  1. 存在-0和0的情况,用int控制输入是不行的。
  2. 超时要用scanf。
#include<bits/stdc++.h>
using namespace std;

const int N = 1100;

int n, T, k;
string x, y;
int a[N];
int st[N];
double e[N][N];

double find (int x) {
	double res = -1;
	for (int i = 0;i < n;i ++) {
		if (st[x] ^ st[i]) 
			res = max (res, e[x][i]);
	}
	return res;
}

int main()
{
	cin >> n >> T;
	while (T --) {
		scanf ("%d", &k);
		for (int i = 0;i < k;i ++) {
			cin >> x;
			a[i] = atoi (x.substr(x[0] == '-').c_str());
			st[a[i]] = (x[0] != '-');
			for (int j = 0;j < i;j ++)
				if (st[a[i]] ^ st[a[j]]) {
					e[a[i]][a[j]] += 1.0 / k;
					e[a[j]][a[i]] += 1.0 / k;
				}
		}
	}
	
	cin >> x >> y;
	
	int xx = atoi (x.substr(x[0] == '-').c_str());
	int yy = atoi (y.substr(y[0] == '-').c_str());
	
	double mx1 = find (xx);
	double mx2 = find (yy);
	
	if (mx1 == e[xx][yy] && mx2 == e[xx][yy]) {
		cout << x << ' ' << y << endl;
	} else {
		for (int i = 0;i < n;i ++)
			if (st[xx] ^ st[i] && e[xx][i] == mx1) 
				cout << x << ' ' << (st[i]==0?"-":"") << i << endl;
		for (int i = 0;i < n;i ++)
			if (st[yy] ^ st[i] && e[yy][i] == mx2)
				cout << y << ' ' << (st[i]==0?"-":"") << i << endl;
	}

	return 0;
}

L2-029 特立独行的幸福 (25 分)

题解链接

L2-030 冰岛人 (25 分)

题解链接

L2-031 深入虎穴 (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int n, st[N], dis[N];
int e[N<<1], ne[N<<1], h[N], idx;

void add (int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void bfs (int x) {
	int ans = 0;
	queue <int> q;
	q.push (x);
	while (q.size()) {
		int t = q.front ();
		q.pop ();
		ans = t;
		for (int i = h[t];~i;i = ne[i]) {
			int j = e[i];
			q.push (j);
		}
	}
	
	cout << ans << endl;
}

int main()
{
	cin >> n;
	memset (h, -1, sizeof h);
	for (int i = 1;i <= n;i ++) {
		int k;
		cin >> k;
		while (k --) {
			int b;
			cin >> b;
			add (i, b);
			st[b] = 1;
		}
	}	
	
	int entry;
	for (int i = 1;i <= n;i ++)
		if (!st[i]) entry = i;
	
	bfs (entry);

	return 0;
}

L2-032 彩虹瓶 (25 分)

吐了,注释地方直接break导致当前行还没输入完,把当前行剩下的货物当作下一次的输入了……debug好久。

而且最可怕的是错的是第一个测试点,第一个测试点15分……

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int n, m, k;
stack <int> s;

int main()
{
	cin >> n >> m >> k;
	while (k --) {
		int task = 1, id, flag = 0;
		while (s.size ()) s.pop ();
		for (int i = 1;i <= n;i ++) {
			cin >> id;
			if (id != task) {
				s.push (id);
				if (s.size () > m) 
					flag = 1;      // 不能break啊!!! 
			} else {
				task ++;
				while (s.size() && s.top() == task) {
					s.pop ();
					task ++;
				}
			}
		}
		if (task > n && !flag) puts ("YES");
		else puts ("NO");
	}	

	return 0;
}

L2-033 简单计算器 (25 分)

太简单了吧(感动)

注意是 n 2   o p   n 1 n_2\space op\space n_1 n2 op n1

#include<bits/stdc++.h>
using namespace std;

int n, num;
char op;
stack <int> s1;
stack <char> s2;

int main()
{
	cin >> n;
	for (int i = 1;i <= n;i ++) cin >> num, s1.push (num);
	for (int i = 1;i < n;i ++) cin >> op, s2.push (op);
	
	while (s1.size() && s2.size()) {
		int a = s1.top (); s1.pop ();
		int b = s1.top (); s1.pop ();
		char op = s2.top (); s2.pop ();
		int ans;
		if (op == '+') ans = b + a;
		else if (op == '-') ans = b - a;
		else if (op == '*') ans = b * a;
		else if (a == 0) {	
			printf ("ERROR: %d/0", b);
			return 0;
		} else {
			ans = b / a;
		}
		if (s1.empty () && s2.empty ()) cout << ans << endl;
		else s1.push (ans);
	}

	return 0;
}

L2-034 口罩发放 (25 分)

狗都不做!什么屁题,仨小时没过。

L2-035 完全二叉树的层序遍历 (25 分)

利用完全二叉树索引的性质操作实现太棒了!

#include<bits/stdc++.h>
using namespace std;
const int N = 100;

int n, tree[N];

void build (int x) { // 根节点的索引值
	if (x > n) return ; 
	build (x << 1); // 左子树根节点的索引值
	build (x << 1 | 1); // 右子树根节点的索引值
	cin >> tree[x]; // 先递归遍历左子树和右子树,再到达根节点,输入根节点
}

int main()
{
	cin >> n;
	build (1);	
	cout << tree[1];
	for (int i = 2;i <= n;i ++) // 以索引方式保存的二叉树按索引顺序遍历就是层序遍历
	cout << ' ' << tree[i];
	return 0;
}

L2-036 网红点打卡攻略 (25 分)

#include<bits/stdc++.h>
using namespace std;

const int N = 300, INF = 0x3f3f3f3f;

int n;
int e[N][N], st[N], a[N], min_cost = INF, min_cost_id;

vector <int> v;

int cost (int m) {
	int s = 0, res = 0;
	a[m+1] = 0; 
	memset (st, 0, sizeof st);
	for (int i = 0;i <= m;i ++) {
		int tmp = e[a[i]][a[i+1]];
		if (tmp == INF || st[a[i]]) return -1;
		res += tmp;
		st[a[i]] = 1;
	}
	for (int i = 1;i <= n;i ++)
		if (!st[i]) return -1;
	return res;	
}

int main()
{
	memset (e, 0x3f, sizeof e);
	
	int k, m;
	cin >> n >> m;
	while (m --) {
		int a, b, c;
		cin >> a >> b >> c;
		e[a][b] = e[b][a] = c;
	}	
	
	cin >> k;
	for (int i = 1;i <= k;i ++) {
		cin >> m;
		for (int j = 1;j <= m;j ++) cin >> a[j];
		int cur_cost = cost(m);
		if (cur_cost != -1) {
			v.push_back (i);
			if (min_cost > cur_cost)
				min_cost_id = i, 
				min_cost = cur_cost;
		}
	}
	
	cout << v.size() << endl << min_cost_id << ' ' << min_cost;
	
	return 0;
}

L2-037 包装机 (25 分)

又是在debug。

注意:

  1. 当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落
  2. 如果轨道已经空了,再按对应的按钮不会发生任何事(就连如果框满了,也不会强制抓物品)

搁这考语文呢!

#include<bits/stdc++.h>
using namespace std;

string ans = "";
string goods[110];
stack <char> s;

int main()
{
	int n, m, mx, op;
	cin >> n >> m >> mx;
	for (int i = 1;i <= n;i ++) 
		cin >> goods[i];

	while (1) {
		cin >> op;
		if (op == -1) break;
		if (op == 0) {
			if (s.size ()) 
				ans += s.top (),
				s.pop ();
		} else if (op >= 1 && op <= n){
			if (goods[op].size ()) {
				if (s.size () == mx) {
					ans += s.top ();
					s.pop ();
				}
				s.push (goods[op][0]),
				goods[op].erase (0, 1);
			}
				
		}
	}	
	
	cout << ans << endl;
	return 0;
}

L2-038 病毒溯源 (25 分)

再次注意记录最大路径长度时要在for外面!

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int n, rt, mx_dis;
int fa[N], dis[N], st[N];
int e[N<<1], ne[N<<1], h[N], idx;
vector <int> v[N];

void add (int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void path (int x, int cnt) {
	if (x == -1) return ;
	path(fa[x], cnt);
	v[cnt].push_back (x);
}

void bfs (int x) {
	queue<int> q;
	dis[x] = 1;
	q.push (x);
	while (q.size()) {
		int t = q.front ();
		q.pop ();
		mx_dis = max (mx_dis, dis[t]); // 尽量不要放在for里面,如果根节点无孩子节点,那么mx_dis就不会被赋值 
		for (int i = h[t];~i;i = ne[i]) {
			int j = e[i];
			dis[j] = dis[t] + 1;
			q.push (j);
			fa[j] = t;
		}
	}
}

int main()
{
	memset (fa, -1, sizeof fa);
	memset (h, -1, sizeof h);
	cin >> n;
	for (int i = 0;i < n;i ++) {
		int k;
		cin >> k;
		while (k --) {
			int b;
			cin >> b;
			add (i, b);
			st[b] = 1;
		}
	}
	for (int i = 0;i < n;i ++)
	if (!st[i]) rt = i;
	
	bfs (rt);
	
	int cnt = 0;
	for (int i = 0;i < n;i ++)
	if (dis[i] == mx_dis) 
		path (i, cnt ++);
	
	sort (v, v + cnt); // 本质是对数组进行排序,数组的元素是vector,使用vector自带的比较函数比较大小,自带的比较函数就是题目要求的 
	
	cout << mx_dis << endl;
	cout << v[0][0];
	for (int i = 1;i < v[0].size();i ++)
		cout << ' ' << v[0][i];
	return 0;
}

L2-039 清点代码库 (25 分)

题解链接

L2-040 哲哲打游戏 (25 分)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int n, m, k, t;
int save[N];
vector <int> plot_selection[N]; // 由于第一维为1e5,第二维只给出了全部和不超过1e6,直接开太大,所以要用vector 
int main()
{
	cin >> n >> m;
	
	for (int  i = 1;i <= n;i ++) {
		cin >> k;
		for (int j = 1;j <= k;j ++) 
			cin >> t, plot_selection[i].push_back (t);
	}	
	
	int cur_plot = 1;
	
	while (m --) {
		int op, j;
		cin >> op >> j;
		if (op == 0) {
			cur_plot = plot_selection[cur_plot][j-1]; // vector从索引0开始加入,所以要j-1 
		} else if (op == 1){
			save[j] = cur_plot;
			cout << cur_plot << endl;
		} else {
			cur_plot = save[j];
		}
	}
	cout << cur_plot << endl;	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值