【数据结构专题】并查集

A、AcWing 1250. 格子游戏

【数据结构专题】并查集_第1张图片
并查集解决的是连通性(无向图联通分量)和传递性(家谱关系)问题,并且可以动态的维护。抛开格子不看,任意一个图中,增加一条边形成环当且仅当这条边连接的两点已经联通,于是可以将点分为若干个集合,每个集合对应图中的一个连通块。

#include

using namespace std;
const int N = 500007;

int n, m;
int fa[N];
bool flag;

int get(int x, int y){
    return x * n + y;
}

int find(int x){
    if(fa[x] == x)return x;
    return fa[x] = find(fa[x]);
}

int main(){
    scanf("%d%d", &n, &m);
    int res;
    
    for(int i = 1;i <= n * n ; ++ i)
        fa[i] = i;
    
    for(int i = 1;i <= m; ++ i){
        int x, y, a, b;
        char op[2];
        scanf("%d%d%s", &x, &y, op);
        x -- , y -- ;
        a = get(x, y);
        if(*op == 'D')
            b = get(x + 1, y);
        else b = get(x, y + 1);
        int aa = find(a), bb = find(b);
        if(aa == bb && !flag){
            res = i;
            flag = true;
        }
        fa[aa] = bb;
    }
    if(res)
    printf("%d\n", res);
    else puts("draw");
    return 0;
}

B、AcWing 1252. 搭配购买

【数据结构专题】并查集_第2张图片

并查集缩点+01背包

可以利用并查集,将这m组配对购买的商品划到一个集合里,这样就可以确定买了其中一个就得买另一个。

//并查集没有办法通过一个点直接找到所有的该集合的点,但是这里我们可以O(n)把属于同一个集合的点缩点,缩成一个物品然后裸一个01背包

#include
#include
#include

using namespace std;

const int N = 50007;

int n, m, k;
int fa[N];
int a[N], b[N];
int c[N], w[N];
int f[N];

int find(int x){
    if(x == fa[x])return x;
    return fa[x] = find(fa[x]);
}

int main(){
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1;i <= n; ++ i)scanf("%d%d", &c[i], &w[i]);
    
    for(int i = 1;i <= n; ++ i)
        fa[i] = i;
        
    for(int i = 1;i <= m; ++ i){
        int x, y;
        scanf("%d%d", &x, &y);
        int fx = find(x), fy = find(y);
        if(fx != fy){
            fa[fx] = fy;
            c[fy] += c[fx];
            w[fy] += w[fx];
        }
    }
    
    for(int i = 1;i <= n; ++ i)
        for(int j = k; j >= c[i]; -- j){
            if(fa[i] == i)
            f[j] = max(f[j], f[j - c[i]] + w[i]);
        }
    printf("%d\n", f[k]);
    return  0;
}

也可以用tarjan缩点+背包

#include
using namespace std;
const int maxn=10000+5;
int money[maxn],fa[maxn];
int c[maxn],d[maxn];
int head[maxn],next[maxn],to[maxn],cnt=0;
int add(int x,int y)
{
	to[++cnt]=y;
	next[cnt]=head[x];
	head[x]=cnt;
}
int dfn[maxn],low[maxn],sum=0;
int st[maxn],top=0;
int col=0,co[maxn];
int a[maxn],b[maxn];
int dp[maxn];
void tarjan(int node)
{
	dfn[node]=low[node]=++sum;
	st[++top]=node;
	for(int i=head[node];i;i=next[i])
	{
		int y=to[i];
		if(!dfn[y])
		{
			tarjan(y);
			low[node]=min(low[node],dfn[y]);
		}
		if(!co[y])
		{
			low[node]=min(low[node],low[y]);
		}
	}
	if(dfn[node]==low[node])
	{
		col++;
		while(st[top]!=node)
		{
			a[col]+=c[st[top]];
			b[col]+=d[st[top]];
			co[st[top]]=col;
			top--;
		}
		a[col]+=c[st[top]];
		b[col]+=d[st[top]];
		co[st[top]]=col;
		top--;
	}
}
int main()
{
	int n,m,s;
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&c[i],&d[i]);
	}
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])
		{
			tarjan(i);
		}
	}
	for(int i=1;i<=col;i++)
	{
		for(int j=s;j>=a[i];j--)
		{
			dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
		}
	}
	printf("%d\n",dp[s]);
	return 0;
}

你可能感兴趣的:(#,第四章,高级数据结构,#,并查集)