并查集:
1.查询(采用了递归的方法)
2.合并、
完整代码模板(联系题目直接套模板)
1.优化前
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
int uset[MAXSIZE];//定义一个足够长的数组
//用下标来表示结点
/*
构造并查集
int size 有多少个节点
*/
void makeSet(int size)
{
for (int i = 1; i < size; i++)
{
//各自为各自的代表
uset[i] = i;
}
}
/*
找到元素所在的集合的代表 如果位于同一集合
*/
int find(int i)
{
if (i == uset[i])
{
return i;
}
return find(uset[i]);
}
void unite(int x, int y)
{
//先找相对应的代表
int x = find(x);
int y = find(y);
if (x == y)
{
return;
}
uset[x] = y;
}
2.优化后
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100
/*
因为在特殊情况下 这棵树可能是一个长长的树链 设链的最后一个节点为x
每次执行find 相当于遍历整个链条
只需要把便利过的结点都改成跟的子节点 查询就会快很多
*/
int uset[MAXSIZE];//定义一个足够长的数组 每个结点
int rank[MAXSIZE];//树的高度
//用下标来表示结点
/*
构造并查集
int size 有多少个节点
*/
void makeSet(int size)
{
for (int i = 1; i <= size; i++)
{
//各自为各自的代表
uset[i] = i;
//树的高度
rank[i] = 0;
}
}
/*
找到元素所在的集合的代表 如果位于同一集合
查找元素在哪个集合
*/
int find(int i)
{
if (i == uset[i])
{
return i;
}
return uset[i] = find(uset[i]);//在第一次查找的时候 将结点直接连到跟
}
void unite(int x, int y)
{
//先找相对应的代表
int x = find(x);
int y = find(y);
if (x == y)
{
return;
}
//判断两棵树的高度 在决定谁为子树
if (rank[x] < rank[y])
{
uset[x] = y;
}
else
{
uset[y] = x;
if (rank[x] == rank[y])
{
rank[x]++;
}
}
}
背包问题:
1.01背包:物品有限,求取最大价值dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
2.完全背包:物品无限,求最大价值dp[j]=max(dp[j],dp[j-w[i]]+v[i])
3.多重背包:每个物品只能拿指定数目