第10章 并查集

A1013



#include<iostream>
using namespace std;

/*
2≤N≤1000,         N表示节点个数
1≤M≤N(N−1)2,     M表示最大边数,每个点除自身外,可以和剩下的n-1个点,相连,所以是n*n(n-1) 注意这样所有的边倍计算了两次,所以最后是n*(n-1)/2

*/

const int maxn=500010;

int n,m,k;

struct node             //边的 结构,一条边上的 两个 点
{
    int a,b;
}Node[maxn];

int p[maxn];

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=0; i<m; i++)
    {
        cin >> Node[i].a >> Node[i].b;
    }
    while(k--)
    {
        int x;
        cin >> x;
        int  cnt=n-1;                //cnt表示 初始化的 连通块个数,由于要去掉一个点,所以 就是刚开始 假设有n-1个连通块

        for(int i=1; i<=n; i++)
            p[i]=i;                              //p数组就是 并查集

        for(int i=0; i<m; i++)     //需要遍历m条边
        {
            int kk=Node[i].a,kk1=Node[i].b;

            if(kk!=x && kk1!=x)        //找到 与要删除的点 无关的边
            {
                int pa=find(kk),pb=find(kk1);

                if(pa!=pb)
                {
                    p[pa]=pb;
                    cnt--;
                }
            }

        }
         cout << cnt-1 << endl;                    //最后的 cnt表示 连通块数,需要求得边 就是 连通块数-1
    }
    return 0;
}

A1114



#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=500010;

struct node
{
    int a,b;
}e[maxn];

int hc[maxn],ha[maxn];         //hc表示id对应的房子个数,ha表示id对应的房子面积

int p[maxn],c[maxn];

bool st[maxn]={false};

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

struct Family
{
    int id,c, hc,ha;
};

bool cmp(Family a,Family b)
{
    if(a.ha*b.c!=b.ha*a.c)
    {
        return a.ha*b.c>b.ha*a.c;
    }
    return a.id<b.id;
}

int main()
{
    int n;
    cin >> n;
    int m=0;            //表示边数
    vector<Family> Node;
    for(int i=0; i<n; i++)
    {
        int id,father,mother,k;
        cin >> id >> father >> mother >> k;
        st[id]=true;
        if(father!=-1)
            e[m++]={id,father};
        if(mother!=-1)
            e[m++]={id,mother};
        for(int j=0; j<k; j++)
        {
            int son;
            cin >> son;
            e[m++]={id,son};
        }
        cin >> hc[id] >> ha[id];         //注意 输入
    }

    for(int i=0; i<maxn; i++)
    {
        p[i]=i;
        c[i]=1;
    }


    for (int i = 0; i < m; i ++ )
    {
        int a = e[i].a, b = e[i].b;

        st[a] = st[b] = true;
        int pa = find(a), pb = find(b);
        if (pa != pb)
        {
            if (pb > pa) swap(pa, pb);
            c[pb] += c[pa];
            hc[pb] += hc[pa];
            ha[pb] += ha[pa];
            p[pa] = pb;
        }
    }

    for(int i=0; i<maxn; i++)
    {
        if(st[i]==true && p[i]==i)
        {
            Node.push_back({i,c[i],hc[i],ha[i]});
        }
    }
    cout << Node.size() << endl;
    sort(Node.begin(),Node.end(),cmp);
    for(int i=0; i<Node.size(); i++)
    {
        printf("%04d %d %.3lf %.3lf\n",Node[i].id,Node[i].c,(double)Node[i].hc/Node[i].c,(double)Node[i].ha/Node[i].c);
    }
}

A1118


#include<iostream>
using namespace std;

const int maxn=10010;

struct node
{
    int a,b;
}Node[maxn];

bool st[maxn];

int n;

int p[maxn];

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

int main()
{
    cin >> n;
    int m=0;
    int temp;
    int niaoshu=0;
    while(n--)
    {
        cin >> temp;

        int temp2,daibiao;
        for(int i=0; i<temp; i++)
        {
            cin >> temp2;
        if(st[temp2]==false)
        {
            st[temp2]=true;
            niaoshu++;
        }
            if(i==0)
                daibiao=temp2;
            if(i!=0)
                Node[m++]={daibiao,temp2};
        }
    }

    for(int i=1; i<=maxn; i++)
        p[i]=i;
    int cnt=niaoshu;

    for(int i=0; i<m; i++)
    {
        int faA=find(Node[i].a),faB=find(Node[i].b);
        if(faA!=faB)
        {
            p[faA]=faB;
            cnt--;
        }
    }
    cout << cnt << " " << niaoshu << endl;
    int kk;
    cin >> kk;
    int wsf,xx;
    while(kk--)
    {
        cin >> wsf >> xx;
        if(find(wsf)==find(xx))
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}

A1107


/*
    题意:每个人给出他的兴趣,然后在根据共有的兴趣,统计出来人数

    1.用vector数组,下标表示兴趣爱好,下面的值是人的编号
    2.由于兴趣爱好的编号是从1---1000,所以需要全部遍历,然后以该下面值的第一个作为根节点,然后进行合并
    3.由于上面的合并 是 以人的 节点 作为 下标,所以 通过遍历 每个 人的 编号,去找到每个人的 编号的 根节点,并统计个数,所以先统计出块数,然后排序,然后输出兴趣下的人数
    
*/

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=1010;

vector<int> xx[maxn];

int p[maxn];

int n;

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

bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    cin >> n;
    int temp;
    for(int T=1; T<=n; T++)
    {
        scanf("%d:",&temp);
        int temp1;
        for(int i=0; i<temp; i++)
        {
            cin >> temp1;
            xx[temp1].push_back(T);
        }
    }

    for(int i=1; i<=n
    ; i++)
        p[i]=i;

    for(int i=1; i<=1000; i++)     //兴趣 最大值 就是 1000
    {
        for(int j=1; j<xx[i].size(); j++)
        {
            int faA=find(xx[i][0]),faB=find(xx[i][j]);
            if(faA!=faB)
                p[faA]=faB;
        }
    }

    int renshu[maxn]={0};
    for(int i=1; i<=n; i++)
    {
            renshu[find(i)]++;
    }

    int ans=0;
    for(int i=1; i<=n; i++)
    {
        if(renshu[i]!=0)
            ans++;
    }
    cout << ans << endl;
    sort(renshu+1,renshu+n+1,cmp);
    for(int i=1; i<=ans; i++)
    {
        if(i!=1)
            cout << " ";
        cout << renshu[i];
    }
}

A1048


#include<iostream>
#include<unordered_set>
using namespace std;

//再输入的 过程 中每次 更新 满足条件的 最小值,

int main()
{
    int n,m;    
    cin >> n >> m;
    unordered_set<int> hash1;
    int v1=1e9,v2;
    for(int i=0; i<n; i++)
    {
        int x;
        cin >> x;
        int y=m-x;
        if(hash1.count(y))
        {
            hash1.insert(x);
            if(x>y)
                swap(x,y);
            if(v1>x)
            {
                v1=x;
                v2=m-v1;
            }
        }
        else
            hash1.insert(x);
    }
    if(v1==1e9)
        cout << "No Solution";
    else
        cout << v1 << " " << v2;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值