PAT甲级——搜索总结

1004 Counting Leaves (30 分)

题目大意
给出一棵树,问每一层各有多少个叶子结点。

方法一:bfs

#include<bits/stdc++.h>
using namespace std;
int n, m, k, mx, cnt[105], mp[105];
vector<int> v[105];
queue<int> q;

void bfs()
{
	q.push(1);
	while(!q.empty()){
		int p = q.front();
		q.pop();
		if(v[p].size() == 0)
			mp[cnt[p]]++;
		for(int i = 0; i < v[p].size(); i++){
			int to = v[p][i];
			cnt[to] = cnt[p] + 1;
			mx = max(mx, cnt[to]);
			q.push(to);
		}
	}
}

int main()
{
	cin >> n >> m;
	for(int i = 0; i < m; i++){
		int id, x;
		cin >> id >> k;
		for(int j = 0; j < k; j++){
			cin >> x;
			v[id].push_back(x);
		}
	}
	bfs();
	for(int i = 0; i <= mx; i++)
		printf("%d%c", mp[i], i == mx ? '\n' : ' ');
	return 0;
}

方法二:dfs

#include<bits/stdc++.h>
using namespace std;
int n, m, k, mx, mp[105];
vector<int> v[105];

void dfs(int id, int depth)
{
	if(v[id].size() == 0){
		mp[depth]++;
		mx = max(mx, depth);
		return ;
	}
	for(int i = 0; i < v[id].size(); i++)
		dfs(v[id][i], depth + 1);
}

int main()
{
	cin >> n >> m;
	for(int i = 0; i < m; i++){
		int id, x;
		cin >> id >> k;
		for(int j = 0; j < k; j++){
			cin >> x;
			v[id].push_back(x);
		}
	}
	dfs(1, 0);
	for(int i = 0; i <= mx; i++)
		printf("%d%s", mp[i], i == mx ? "\n" : " ");
	return 0;
}

1021 Deepest Root (25 分)

题目大意
给出一个正整数 n,表示有 n 个结点,分别为 1 ~ n,并给出 n - 1 条边,问是否能构成一棵树,如果不能,则输出其连通分量的个数,如果能,则输出能构成最深的树的高度时,树的根结点。如果有多个,就按照从小到大的顺序输出。

分析
先用 dfs 来计算它连通分量的个数,若存在多个连通分量,就输出 Error: x components,如果只有一个,就取第一次深搜得到的深度最深的任意一个结点,再对其进行一次 dfs,两次搜索得到的结点的并集就是我们所求的结果了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
int n, m, mx, vis[maxn];
vector<int> v[maxn], f;
set<int> s;

void dfs(int x, int h)
{
	if(h > mx){
		f.clear();
		f.push_back(x);
		mx = h;
	}
	else if(h == mx)
		f.push_back(x);
	vis[x] = 1;
	for(int i = 0; i < v[x].size(); i++){
		if(!vis[v[x][i]])
			dfs(v[x][i], h + 1);
	}
}

int main()
{
	cin >> n;
	for(int i = 1; i < n; i++){
		int a, b;
		cin >> a >> b;
		v[a].push_back(b);
		v[b].push_back(a);
	}
	int root = 0, num = 0;
	for(int i = 1; i <= n; i++){
		if(!vis[i]){
			dfs(i, 1);
			if(i == 1){
				if(f.size() != 0)
					m = f[0];
				for(int j = 0; j < f.size(); j++)
					s.insert(f[j]);
			}
			num++;
		}
	}
	if(num > 1){
		printf("Error: %d components\n", num);
	}
	else{
		f.clear();
		mx = 0;
		memset(vis, 0, sizeof(vis));
		dfs(m, 1);
		for(int i = 0; i < f.size(); i++)
			s.insert(f[i]);
		for(auto it : s)
			printf("%d\n", it);
	}
	return 0;
}

1076 Forwards on Weibo (30 分)

题目大意
给定两个正整数 n, l,分别表示用户数量和最多转发层数,而用户 id 用 1 ~ n 表示,然后再给出每个用户关注的人的 id,求某个 id 发了微博后最多会有多少人转发。

分析
用 bfs 搜索在 l 层范围内的即可,但需要注意的是,每个用户只能转发一次,所以还需定义一个 vis 数组判断其是否入队过。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e3 + 10;
int n, l, m, uid, k, cnt, vis[maxn];
vector<int> v[maxn];

void bfs()
{
	memset(vis, 0, sizeof(vis));
	cnt = 0;
	priority_queue<pii, vector<pii>, greater<pii> > q;
	q.push({0, uid});
	vis[uid] = 1;
	while(!q.empty()){
		pii p = q.top();
		q.pop();
		int m = p.second;
		for(int i = 0; i < v[m].size(); i++){
			int level = p.first + 1;
			if(!vis[v[m][i]] && level <= l){
				cnt++;
				vis[v[m][i]] = 1;
				q.push({level, v[m][i]});
			}
		}
	}
}

int main()
{
	cin >> n >> l;
	for(int i = 1; i <= n; i++){
		cin >> m;
		for(int j = 1; j <= m; j++){
			int x;
			cin >> x;
			v[x].push_back(i);
		}
	}
	cin >> k;
	for(int i = 1; i <= k; i++){
		cin >> uid;
		bfs();
		cout << cnt << endl;
	}
	return 0;
}

1079 Total Sales of Supply Chain (25 分)

题目大意
给定一棵树,树根的价格为 p,从根结点开始,每往下一层,价格就上涨 r%,叶节点表示零售商,给出叶节点的货物量,求它们的价格之和。

方法一:bfs

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e5 + 10;
int n, k, f[maxn], cnt[maxn], vis[maxn];
double p, r;
vector<int> v[maxn];

void bfs(int s)
{
	memset(vis, 0, sizeof(vis));
	cnt[s] = 0;
	priority_queue<pii, vector<pii>, greater<pii> > q;
	q.push({0, s});
	while(!q.empty()){
		pii p = q.top();
		q.pop();
		int m = p.second;
		if(vis[m])
			continue;
		vis[m] = 1;
		for(int i = 0; i < v[m].size(); i++){
			int tt = v[m][i];
			cnt[tt] = cnt[m] + 1;
			q.push({cnt[tt], tt});
		}
	}
}

int main()
{
	cin >> n >> p >> r;
	for(int i = 0; i < n; i++){
		cin >> k;
		for(int j = 0; j < k; j++){
			int x;
			cin >> x;
			v[i].push_back(x);
		}
		if(k == 0){
			int x;
			cin >> x;
			f[i] = x;
		}
	}
	bfs(0);
	double sum = 0;
	for(int i = 0; i < n; i++)
		if(f[i] != 0)
			sum += p * pow(1 + r / 100, cnt[i]) * f[i];
	printf("%.1lf\n", sum);
	return 0;
}

方法二:dfs

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e5 + 10;
int n, k, f[maxn], cnt[maxn], vis[maxn];
double p, r;
vector<int> v[maxn];

void dfs(int s, int level)
{
	if(v[s].size() == 0){
		cnt[s] = level;
		return ;
	}
	for(int i = 0; i < v[s].size(); i++)
		dfs(v[s][i], level + 1);
}

int main()
{
	cin >> n >> p >> r;
	for(int i = 0; i < n; i++){
		cin >> k;
		for(int j = 0; j < k; j++){
			int x;
			cin >> x;
			v[i].push_back(x);
		}
		if(k == 0){
			int x;
			cin >> x;
			f[i] = x;
		}
	}
	dfs(0, 0);
	double sum = 0;
	for(int i = 0; i < n; i++)
		if(f[i] != 0)
			sum += p * pow(1 + r / 100, cnt[i]) * f[i];
	printf("%.1lf\n", sum);
	return 0;
}

1091 Acute Stroke (30 分)

题目大意
给定一个三维数组,0 表示正常,1 表示有肿瘤,肿瘤块的大小大于等于 t 才算是肿瘤,计算所有满足肿瘤块的大小。

#include<bits/stdc++.h>
using namespace std;
int m, n, l, t, f[1300][130][70], vis[1300][130][70];
int dx[6] = {1, -1, 0, 0, 0, 0};
int dy[6] = {0, 0, 1, -1, 0, 0};
int dz[6] = {0, 0, 0, 0, 1, -1};

struct node{
	int x, y, z;
};

bool judge(int x, int y, int z)
{
	if(x < 0 || x >= m || y < 0 || y >= n || z < 0 || z >= l)
		return false;
	if(f[x][y][z] == 0 || vis[x][y][z])
		return false;
	return true;
}

int bfs(int x, int y, int z)
{
	queue<node> q;
	q.push({x, y, z});
	vis[x][y][z] = 1;
	int cnt = 0;
	while(!q.empty()){
		node p = q.front();
		q.pop();
		cnt++;
		for(int i = 0; i < 6; i++){
			int xx = p.x + dx[i];
			int yy = p.y + dy[i];
			int zz = p.z + dz[i];
			if(judge(xx, yy, zz)){
				q.push({xx, yy, zz});
				vis[xx][yy][zz] = 1;
			}
		}
	}
	if(cnt >= t)
		return cnt;
	else
		return 0;
}

int main()
{
	cin >> m >> n >> l >> t;
	for(int i = 0; i < l; i++){
		for(int j = 0; j < m; j++){
			for(int k = 0; k < n; k++){
				cin >> f[j][k][i];
			}
		}
	}
	int sum = 0;
	for(int i = 0; i < l; i++){
		for(int j = 0; j < m; j++){
			for(int k = 0; k < n; k++){
				if(f[j][k][i] == 1 && !vis[j][k][i]){
					sum += bfs(j, k, i);
				}
			}
		}
	}
	cout << sum << endl;
	return 0;
}

1094 The Largest Generation (25 分)

题目大意
给定一棵树,求结点个数最多的一层,输出其结点个数及层号。

方法一:bfs

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int n, m, k, id, mx, mxLevel, cnt[105];
vector<int> v[105];
map<int, int> mp;

void bfs(int s)
{
	queue<int> q;
	q.push(s);
	cnt[s] = 1;
	while(!q.empty()){
		int p = q.front();
		q.pop();
		mp[cnt[p]]++;
		for(int i = 0; i < v[p].size(); i++){
			int tt = v[p][i];
			cnt[tt] = cnt[p] + 1;
			q.push(tt);
		}
	}
	return ;
}

int main()
{
	cin >> n >> m;
	for(int i = 1; i <= m; i++){
		cin >> id >> k;
		for(int i = 1; i <= k; i++){
			int x;
			cin >> x;
			v[id].push_back(x);
		}
	}
	bfs(1);
	int ans = 0, ansLevel = 1;
	for(int i = 1; i <= 100; i++){
		if(mp[i] > ans){
			ans = mp[i];
			ansLevel = i;
		}
	}
	cout << ans << " " << ansLevel << endl;
	return 0;
}

方法二:dfs

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
int n, m, k, id, mx, mxLevel;
vector<int> v[105];
map<int, int> mp;

void dfs(int s, int level)
{
	mp[level]++;
	for(int i = 0; i < v[s].size(); i++){
		dfs(v[s][i], level + 1);
	}
}

int main()
{
	cin >> n >> m;
	for(int i = 1; i <= m; i++){
		cin >> id >> k;
		for(int i = 1; i <= k; i++){
			int x;
			cin >> x;
			v[id].push_back(x);
		}
	}
	dfs(1, 1);
	int ans = 0, ansLevel = 1;
	for(int i = 1; i <= 100; i++){
		if(mp[i] > ans){
			ans = mp[i];
			ansLevel = i;
		}
	}
	cout << ans << " " << ansLevel << endl;
	return 0;
}

1103 Integer Factorization (30 分)

题目大意
给定正整数 n,k,p,问是否存在 k 个数,每个数的 p 次方之和为 n,若存在多组,则输出因子总和最大的一组。

#include<bits/stdc++.h>
using namespace std;
int n, k, p, mx, a[405], ans[405];

void dfs(int x, int num, int sum, int fac)
{
	if(x > n || num > k)
		return ;
	if(x == n && num == k){
		if(mx < sum){
			for(int i = 0; i < num; i++)
				ans[i] = a[i];
			mx = sum;
		}	
		return ;
	}
	for(int i = fac; i >= 1; i--){
		a[num] = i;
		dfs(x + pow(i, p), num + 1, sum + i, i);
	}
}

int main()
{
	cin >> n >> k >> p;
	dfs(0, 0, 0, sqrt(n));
	if(mx != 0){
		sort(ans, ans + k);
		printf("%d = %d^%d", n, ans[k-1], p);
		for(int i = k-2; i >= 0; i--)
			printf(" + %d^%d", ans[i], p);
		printf("\n");
	}
	else
		printf("Impossible\n");
	return 0;
}

1106 Lowest Price in Supply Chain (25 分)

题目大意
给定一棵树,树根处的价格为 p,从根结点开始,每往下一层,该层货物的价格就会在其父亲结点的价格上增加 r%。在叶子结点处能获得的最低价格,及能提供最低价格的叶子结点数。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, k, mn, num, cnt[maxn];
double p, r;
vector<int> f[maxn];

void dfs(int s)
{
	if(f[s].size() == 0){
		if(mn > cnt[s]){
			mn = cnt[s];
			num = 1;
		}
		else if(mn == cnt[s])
			num++;
	}
	for(int i = 0; i < f[s].size(); i++){
		cnt[f[s][i]] = cnt[s] + 1;
		dfs(f[s][i]);
	}	
}

int main()
{
	cin >> n >> p >> r;
	for(int i = 0; i < n; i++){
		cin >> k;
		for(int j = 0; j < k; j++){
			int x;
			cin >> x;
			f[i].push_back(x);
		}
	}
	mn = 0x3f3f3f3f;
	num = 0;
	dfs(0);
	printf("%.4lf %d\n", p * pow(1 + r/100, mn), num);
	return 0;
}

1127 ZigZagging on a Tree (30 分)

题目大意
给定一棵树的中序和后序遍历结果,求它的 Z 型层序遍历,即奇数层从左往右遍历,偶数层从右往左遍历。

#include<bits/stdc++.h>
using namespace std;
int n;
vector<int> in, post;

struct node{
	int a, b, c;
};

bool cmp(node x, node y){
	if(x.b == y.b){
		if(x.b % 2)
			return x.c > y.c;
		else
			return x.c < y.c;
	}
	return x.b < y.b;
}
vector<node> ans;


void dfs(int root, int l, int r, int index, int depth)
{
	if(l > r)
		return ;
	int i = l;
	while(in[i] != post[root] && i <= r) i++;
	ans.push_back({post[root], depth, index});
	dfs(root - (r - i + 1), l, i - 1, index * 2 + 1, depth + 1);
	dfs(root - 1, i + 1, r, index * 2 + 2, depth + 1);
}

int main()
{
	cin >> n;
	in.resize(n + 1);
	post.resize(n + 1);
	for(int i = 1; i <= n; i++)
		cin >> in[i];
	for(int i = 1; i <= n; i++)
		cin >> post[i];
	dfs(n, 1, n, 1, 1);
	sort(ans.begin(), ans.end(), cmp);
	for(int i = 0; i < ans.size(); i++)
		printf("%d%s", ans[i].a, i == ans.size() - 1 ? "\n" : " ");
	return 0;
}

1130 Infix Expression (25 分)

题目大意
给定一棵二叉树,输出它的中缀表达式,并加上括号表示运算的优先级。

#include<bits/stdc++.h>
using namespace std;
int n, root = 1;

struct node{
	string val;
	int l, r;
};

vector<node> v;

string dfs(int index)
{
	if(index == -1) return "";
	if(v[index].r != -1){
		v[index].val = dfs(v[index].l) + v[index].val + dfs(v[index].r);
		if(index != root) v[index].val = '(' + v[index].val + ')';
	}
	return v[index].val;
}

int main()
{
	cin >> n;
	v.resize(n + 1);
	vector<bool> vis(n + 1, false);
	for(int i = 1; i <= n; i++){
		cin >> v[i].val >> v[i].l >> v[i].r;
		if(v[i].l != -1) vis[v[i].l] = true;
		if(v[i].r != -1) vis[v[i].r] = true;
	}
	while(vis[root] == true) root++;
	cout << dfs(root) << endl;
	return 0;
}

1131 Subway Map (30 分)

题目大意
给定起点和终点,要求你给出一条路线,使得中途停站最少,如果停站数量一样多,就选择换乘线路次数最少的路线。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, m, k, pre, minCnt, minTransfer, st, ed;
vector<int> v[maxn], path, tempPath;
unordered_map<int, int> line;
int vis[maxn];

int func(vector<int> a)
{
	int num = 0, preLine = line[a[0] * 10000 + a[1]];
	for(int i = 1; i < a.size(); i++){
		if(line[a[i] * 10000 + a[i + 1]] != preLine)
			num++;	
		preLine = line[a[i] * 10000 + a[i + 1]];
	}
	return num;
}

void dfs(int node, int cnt)
{
	if(node == ed && (cnt < minCnt || (func(tempPath) < minTransfer && cnt == minCnt))){
		minCnt = cnt;
		minTransfer = func(tempPath);
		path = tempPath;
	}
	if(node == ed) return ;
	for(int i = 0; i < v[node].size(); i++){
		if(!vis[v[node][i]]){
			vis[v[node][i]] = 1;
			tempPath.push_back(v[node][i]);
			dfs(v[node][i], cnt + 1);
			vis[v[node][i]] = 0;
			tempPath.pop_back();
		}
	}
}

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i++){
		cin >> m >> pre;
		for(int j = 1; j < m; j++){
			int x;
			cin >> x;
			v[pre].push_back(x);
			v[x].push_back(pre);
			line[pre * 10000 + x] = line[x * 10000 + pre] = i;
			pre = x;
		}
	}
	cin >> k;
	while(k--){
		cin >> st >> ed;
		minCnt = 99999, minTransfer = 99999;
		memset(vis, 0, sizeof(vis));
		tempPath.clear();
		tempPath.push_back(st);
		path.clear();
		vis[st] = 1;
		dfs(st, 0);
		vis[st] = 0;
		cout << minCnt << endl;
		int preLine = line[path[0] * 10000 + path[1]], preNode = path[0];
		for(int i = 1; i < path.size(); i++){
			if(line[path[i] * 10000 + path[i + 1]] != preLine){
				printf("Take Line#%d from %04d to %04d.\n", preLine, preNode, path[i]);
				preLine = line[path[i] * 10000 + path[i + 1]];
				preNode = path[i];
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值