算法刷题记录(Day 29)

本文介绍了两道经典POJ题目:“ClosestCommonAncestors”利用Tarjan算法解决最近公共祖先问题;“ShortestPrefixes”通过字典树高效求解字符串集合中最短唯一前缀。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Closest Common Ancestors(poj 1470)

原题链接
题目类型:lca模板
使用tarjan来离线求取lca问题。
tarjan求lca

//TLE
#include<iostream>
#include<vector>
using namespace std;
#define NMAX 950
struct edge {
	short from, to;
	short lca, nxt;
};
vector<edge> E;
short h[NMAX];
vector<edge> Q;
short qh[NMAX];
short res[NMAX], du[NMAX], color[NMAX];
char vis[NMAX];
short n, m;
short root;
short find(short x) {
	if (x != color[x]) color[x] = find(color[x]);
	return color[x];
}
void tarjan(short x,short fa) {
	vis[x] = 1;
	color[x] = x;
	for (short i = h[x]; i != -1; i = E[i].nxt) {
		if (!vis[E[i].to]) {
			tarjan(E[i].to,x);
		}
	}
	color[x] = fa;
	for (short i = qh[x]; i != -1; i = Q[i].nxt) {
		if (vis[Q[i].to] && !Q[i].lca) {
			short LCA = find(Q[i].to);
			Q[i].lca = LCA;
			Q[i ^ 1].lca = LCA;
			res[LCA]++;
		}
	}
}
int main() {
	while (~scanf_s("%d", &n)) {
		memset(du, 0, sizeof(du));
		memset(h, -1, sizeof(h));
		memset(qh, -1, sizeof(qh));
		memset(res, 0, sizeof(res));
		Q.clear();
		E.clear();

		char c;
		for (short i = 0; i < n; i++) {
			short a, b, num;
			scanf_s("%d:(%d)", &a, &num);
			for (short j = 0; j < num; j++) {
				scanf_s("%d", &b);
				edge cur;
				du[b]++;
				cur.from = a, cur.to = b, cur.lca = 0, cur.nxt = h[a];
				h[a] = E.size();
				E.push_back(cur);

				cur.from = b, cur.to = a, cur.lca = 0, cur.nxt = h[b];
				h[b] = E.size();
				E.push_back(cur);
			}
		}
		for (short i = 1; i <= n; i++) {
			if (!du[i]) {
				root = i;
				break;
			}
		}
		cin >> m;
		for (short i = 0; i < m; i++) {
			short a, b;
			scanf_s(" (%d %d)", &a, &b);

			edge cur;
			cur.from = a, cur.to = b, cur.lca = 0, cur.nxt = qh[a];
			qh[a] = Q.size();
			Q.push_back(cur);

			cur.from = b, cur.to = a, cur.lca = 0, cur.nxt = qh[b];
			qh[b] = Q.size();
			Q.push_back(cur);
		}

		//首先自己染色自己
		memset(vis, 0, sizeof(vis));
		tarjan(root, root);

		//for (short i = 0; i < Q.size(); i++) cout << Q[i].from << " " << Q[i].to << " " << Q[i].lca << endl;
		for (short i = 1; i <= n; i++) {
			if (res[i]) cout << i << ":" << res[i] << endl;
		}
	}
}

限时两秒,超时不应该呀,明天再看!

Shortest Prefixes(poj 2001)

原题链接
题目类型:tire字典树

错误思路一:逐位寻找,只有当该位的字符没有在其余字符串中出现时,表示可以作为前缀。

//wa
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector<string> S;
vector<string> R(1010);
vector<char> cur;
int main() {
	string line;
	FILE* stream;
	freopen_s(&stream, "C:\\Users\\芙茗\\Desktop\\test2.in", "r", stdin);
	while (getline(cin, line)) S.push_back(line);

	for (int i = 0; i < 20; i++) {
		cur.clear();
		for (int j = 0; j < S.size(); j++) {
			if (!R[j].size() && i < S[j].size()) cur.push_back(S[j][i]);
		}
		for (int j = 0; j < S.size(); j++) {
			if (!R[j].size() && i < S[j].size()){
				int num = count(cur.begin(), cur.end(), S[j][i]);
				if((num == 1 || i == S[j].size() - 1)) R[j] = S[j].substr(0, i + 1);
			}
		}
	}
	for (int i = 0; i < S.size(); i++) cout << S[i] << " " << R[i] << endl;
}

错误思路二:爆搜 时间复杂度为O(1000100020),但是超时

//tle
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
vector<string> S;
vector<string> S2;
map<string,string> R;
vector<char> cur;
int main() {
	string line;
	//FILE* stream;
	//freopen_s(&stream, "C:\\Users\\芙茗\\Desktop\\test2.in", "r", stdin);
	while (getline(cin, line)) S.push_back(line), S2.push_back(line);
	sort(S.begin(), S.end());
	for (int i = 0; i < S.size(); i++) {
		int lot=S[i].size();
		for (int j = 1; j <= S[i].size(); j++) {
			int key = 1;
			for (int k = 0; k < S.size(); k++) {
				if (k != i && S[i].substr(0, j) == S[k].substr(0, j)) key = 0;
			}
			if (key) {
				lot = j;
				break;
			}
		}
		R[S[i]] = S[i].substr(0, lot);
	}
	for (int i = 0; i < S2.size(); i++) cout << S2[i] << " " << R[S2[i]] << endl;
}

思路三:采用字典树

#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<string> S;

struct node {
	int count;
	struct node* son[26];
	//初始化函数
	node() {
		count = 0;
		int i = 0;
		for (; i < 26; i++) son[i] = NULL;
	}
};
struct node* root;
void insert(string x) {
	struct node* cur = root;
	for (int i = 0; i < x.size(); i++) {
		int num = x[i] - 'a';
		if (cur->son[num] == NULL) {
			cur->son[num] = new node;
			++((cur->son[num])->count);
			cur = cur->son[num];
		}
		else {
			cur = cur->son[num];
			++(cur->count);
		}
	}
}
void query(string x) {
	struct node* cur = root;
	string res;
	for (int i = 0; i < x.size(); i++) {
		int num = x[i] - 'a';
		cur = cur->son[num];
		if (cur->count == 1) {
			res += x[i];
			cout << x << " " << res << endl;
			return;
		}
		res += x[i];
	}
	cout << x << " " << x << endl;
}
int main() {
	//FILE* stream;
	//freopen_s(&stream, "C:\\Users\\芙茗\\Desktop\\test2.in", "r", stdin);

	string line;
	while (getline(cin, line)) S.push_back(line);
	root = new node;
	for (int i = 0; i < S.size(); i++) {
		insert(S[i]);
	}
	for (int i = 0; i < S.size(); i++) query(S[i]);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值