文章目录
牛的语言学
考察知识:递推
题目链接
https://www.acwing.com/problem/content/5559/
题目描述
思路
具体代码及注释
#include <iostream>
#include <set>
using namespace std;
const int N = 10010;
bool f[N];
//用递推,f[i]表示f[0...i]可以作为一个词根
int main() {
string s;
cin >> s;
set<string> res; //用set存储,防止重复,而且排序好了
int n = s.size();
f[n - 1] = true;
//从后往前递推
for(int i = n - 2; i >= 4; i --) { //保证最少词根有5个长度
//枚举后缀长度
for(int j = 2; j <= 3; j++) {
//判断后边跟着的第一个后缀是否满足
if(f[i + j]) { //从后往前,故f[i + j]已经操作好了,若是可以作为词根,那么操作后缀判断
//取出后缀和其后相邻的后缀进行判断
string a = s.substr(i + 1, j);
string b = s.substr(i + 1 + j, j);
//判断是否相等,不相等或者长度不一样则满足条件
if(a != b || f[i + 5]) {
f[i] = true;
res.insert(a); //每次其相邻的第一个后缀进行加入即可
}
}
}
}
cout << res.size() << endl;
for(auto &it : res) cout << it << endl;
return 0;
}
孤立点数量
考察知识:并查集
题目链接
https://www.acwing.com/problem/content/5560/
题目描述
思路分析
代码及注释
#include <iostream>
using namespace std;
const int N = 100010;
int p[N];
bool st[N]; //判断是否有环
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
//并查集的初始化
for(int i = 1; i <= n; i++) p[i] = i;
while(m --) {
int a, b;
scanf("%d%d", &a, &b);
a = find(a), b = find(b); //找集合的父节点
if(a == b) st[b] = true; //若已经在一个集合中,这时候加边必然会产生环
else {
p[a] = b; //连接a到b的集合中
st[b] |= st[a]; //若a存在环,则b也必然存在了
}
}
//遍历
int res = 0;
for(int i = 1; i <= n; i++)
if(p[i] == i && !st[i]) //(p[i] == i)遍历所有集合代表节点,若无环,则res = 1,累加
res++;
cout <<res;
return 0;
}
【搭配购买】
[题目链接]
https://www.acwing.com/problem/content/1254/
[题目描述]
[AC代码]
#include <iostream>
using namespace std;
const int N = 10010;
int w[N], v[N], p[N];
int f[N];
int n, m, k;
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++) p[i] = i;
for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
while(m --) {
int a, b;
cin >> a >> b;
int pa = find(a), pb = find(b);
if(pa != pb) {
w[pb] += w[pa];
v[pb] += v[pa];
p[pa] = pb;
}
}
for(int i = 1; i <= n; i ++) {
if(p[i] == i)
for(int j = k; j >= v[i]; j --)
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
cout << f[k] << endl;
return 0;
}
【程序自动分析】
题目连接
https://www.acwing.com/problem/content/239/
题目描述
【AC代码】
#include <iostream>
#include <cstring>
#include <unordered_map> //用来存储离散化,因为此题不需要保序
using namespace std;
const int N = 200010; //每个n最多用两个数,故最大范围为2倍n
int n, m;
int p[N];
unordered_map<int, int> S;
struct node{
int x, y, e; //位置和状态(是否相等)
}query[N];
//不保序离散化操作
int get(int x) {
if(S.count(x) == 0) S[x] = ++ n; //创建一个下标点
return S[x];
}
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main() {
int T;
scanf("%d", &T);
while(T --) {
S.clear();
n = 0; //对于每个问题,重新进行离散下标编号
scanf("%d", &m);
//存储值并进行离散化
for(int i = 0; i < m; i ++) {
int x, y, e;
scanf("%d%d%d", &x, &y, &e);
query[i] = {get(x), get(y), e};
}
//初始化每个单集合
for(int i = 1; i <= n; i ++) p[i] = i;
//对相等条件进行并查集合并
for (int i = 0; i < m; i ++ )
if (query[i].e == 1)
{
int pa = find(query[i].x), pb = find(query[i].y);
p[pa] = pb;
}
//对不相等条件进行检索
bool has_conflict = false;
for(int i = 0; i < m; i ++)
if(query[i].e == 0) {
if(find(query[i].x) == find(query[i].y)) {
has_conflict = true;
break;
}
}
if(has_conflict) puts("NO");
else puts("YES");
}
return 0;
}