3月24日成长变换

  1. 并查集的使用
  2. 开始训练dp思维

并查集的使用

题目:来自acwing的并查集使用

一共有 n 个数,编号是 1∼n

,最开始每个数各自在一个集合中。

现在要进行 m

个操作,操作共有两种:

  1. M a b,将编号为 a

和 b

  • 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  • Q a b,询问编号为 a
  • 和 b
    1. 的两个数是否在同一个集合中;

    输入格式

    第一行输入整数 n

    和 m

    接下来 m

    行,每行包含一个操作指令,指令为 M a bQ a b 中的一种。

    输出格式

    对于每个询问指令 Q a b,都要输出一个结果,如果 a

    和 b

    在同一集合内,则输出 Yes,否则输出 No

    每个结果占一行。

    数据范围

    1≤n,m≤105

    输入样例:

    4 5
    M 1 2
    M 3 4
    Q 1 2
    Q 1 3
    Q 3 4
    

    输出样例:

    Yes
    No
    Yes
    
#include 
int p[100100];
using namespace std;

int found(int x) {
	if (x != p[x])//如果我自己不是自己的祖先就是说我还没有找到我的老板
		p[x] = found(p[x]);//就去找我的老板的老板
	return p[x];
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i <= n; i++)
		p[i] = i;//先假设我自己是我自己老板
	while (m--) {
		char s[5];
		int a, b;
		cin >> s >> a >> b;
		if (s[0] == 'M')
			p[found(a)] = found(b);//然后把a的节点接到b祖先上
		else {
			if (found(a) == found(b))//判断他的祖先是不是相等得
				cout << "Yes" << endl;
			else
				cout << "No" << endl;
		}
	}
}

并查集进阶

给定一个包含 n 个点(编号为 1∼n

)的无向图,初始时图中没有边。

现在要进行 m

个操作,操作共有三种:

  1. C a b,在点 a

和点 b 之间连一条边,a 和 b

  • 可能相等;
  • Q1 a b,询问点 a
  • 和点 b 是否在同一个连通块中,a 和 b
  • 可能相等;
  • Q2 a,询问点 a
  1. 所在连通块中点的数量;

输入格式

第一行输入整数 n

和 m

接下来 m

行,每行包含一个操作指令,指令为 C a bQ1 a bQ2 a 中的一种。

输出格式

对于每个询问指令 Q1 a b,如果 a

和 b

在同一个连通块中,则输出 Yes,否则输出 No

对于每个询问指令 Q2 a,输出一个整数表示点 a

所在连通块中点的数量

每个结果占一行。

数据范围

1≤n,m≤105

输入样例:

5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5

输出样例:

Yes
2
3

 

#include 
using namespace std;
int p[100010];
int cnt[100010];

int find(int x) {//找到父亲的节点
	if (p[x] != x)//如果没有找到他的节点
		p[x] = find(p[x]);//那就去找他节点的节点
	return p[x];
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		p[i] = i;
		cnt[i] = 1;
	}
	while (m--) {
		char s[5];
		cin >> s;
		if (s[0] == 'C') {
			int a, b;
			cin >> a >> b;
			a = find(a), b = find(b);//只可以写成这种
			if ((a) != (b)) {//这里有一个容易错的地方,
				//就是不考虑a==b,然后还继续加了节点就是错误
				p[(a)] = (b);
				cnt[(b)] += cnt[(a)];
			}
		} else if (s[1] == '1') {
			int a, b;
			cin >> a >> b;
			if (p[find(a)] == p[find(b)])//判断他们的父亲是否相同
				printf("Yes\n");
			else
				cout << "No" << endl;
		} else {
			int a;
			cin >> a;
			cout << cnt[find(a)] << endl;//找到他父亲的节点,然后输出底下到底
			//多少个好大儿
		}
	}
}

注意:这里有几个错误的地方

第一个就是合并的时候,我要判断a与b的祖先是不是一样。如果是一样的,那么节点数量没有必要增加

第二个就是不相等的时候,如果我没有提前保留不相等的a,b的祖先,并且我在合并之后才做数量统计就是错误的,就相当于我自身增加。

力扣dp专题

题目

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber
 

class Solution {
public:
    int rob(vector& nums) {
        if(nums.empty())//如果是空的就代表我没有必要进行判断
        {
            return 0;
        }
        if(nums.size()==1)
        return nums[0];
        else
        if(nums.size()==2)
        return max(nums[0],nums[1]);//在第一个房子和第二个房子选择利益最大化
           int n=nums.size();
       int dp[210];
       memset(dp,0,sizeof(dp));
        dp[0]=nums[0];
        dp[1]=max(nums[1],nums[0]);
        for(int i=2;i

未完成:

dp 5道题目

八皇后

字符串哈希表

3个图论最短路径

如果今天完成了的话,还会后续更新。

以后会继续连更,请各位见证我的成长吧。

我很菜,但是我会努力的

你可能感兴趣的:(算法,动态规划,leetcode,c++,c语言)