本次训练共5题,本文附AC代码和题目链接。

之前已经学过并查集和最小生成树了(点击此处为上次训练题),今天在洛谷上面复习一下。

洛谷 P1536 村村通

#include <bits/stdc++.h>
using namespace std;
const int N=1010,M=2e5+10;
int n,m,cnt,ans,pre[N];
struct node
{
    int x,y;
}p[M<<1];
int find(int x)
{
    if(pre[x]!=x)pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n&&n)
    {
        cin>>m;
        for(int i=1;i<=n;i++)
            pre[i]=i;
        for(int i=1;i<=m;i++)
            cin>>p[i].x>>p[i].y;
        cnt=0;
        for(int i=1;i<=m;i++)
        {
            if(find(p[i].x)!=find(p[i].y))
            {
                cnt++;
                join(p[i].x,p[i].y);
            }
            if(cnt==n-1)break;
        }
        cnt==n-1?printf("0\n"):printf("%d\n",n-1-cnt);
    }
    return 0;
}

洛谷 P3366 【模板】最小生成树

#include <bits/stdc++.h>
using namespace std;
const int N=5010,M=2e5+10;
int n,m,cnt,ans,pre[N];
struct node
{
    int x,y,val;
}p[M<<1];
bool cmp(node a,node b)
{return a.val<b.val;}
int find(int x)
{
    if(pre[x]!=x)pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=m;i++)
        cin>>p[i].x>>p[i].y>>p[i].val;
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(p[i].x)!=find(p[i].y))
        {
            cnt++;
            join(p[i].x,p[i].y);
            ans=ans+p[i].val;
        }
        if(cnt==n-1)break;
    }
    cnt<n-1?printf("orz\n"):printf("%d\n",ans);
    return 0;
}

洛谷 P1547 Out of Hay

#include <bits/stdc++.h>
using namespace std;
const int N=2010,M=1e4+10;
int n,m,k,mx,cnt,pre[N];
struct node
{
    int x,y,val;
}p[M<<1];
bool cmp(node a,node b)
{return a.val<b.val;}
int find(int x)
{
    if(pre[x]!=x)pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=m;i++)
        cin>>p[i].x>>p[i].y>>p[i].val;
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(p[i].x)!=find(p[i].y))
        {
            cnt++;
            join(p[i].x,p[i].y);
            mx=max(mx,p[i].val);
        }
        if(cnt==n-1)break;
    }
    printf("%d\n",mx);
    return 0;
}

洛谷 P1195 口袋的天空

#include <bits/stdc++.h>
using namespace std;
const int N=1010,M=1e4+10;
int n,m,k,cnt,ans,pre[N];
struct node
{
    int x,y,val;
}p[M<<1];
bool cmp(node a,node b)
{return a.val<b.val;}
int find(int x)
{
    if(pre[x]!=x)pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=m;i++)
        cin>>p[i].x>>p[i].y>>p[i].val;
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(p[i].x)!=find(p[i].y))
        {
            cnt++;
            join(p[i].x,p[i].y);
            ans=ans+p[i].val;
        }
        if(cnt==n-k)break;//如果要连成k个连通分量,则要连的边的数量必然为n-k(可以由单个树的性质m=n-1得到)
    }
    cnt<n-k?printf("No Answer\n"):printf("%d\n",ans);
    return 0;
}

洛谷 P2820 局域网

“除去一些边,使得网络中没有回路,并且被除去网线的权值和最大”
等价于“找到网络的最小生成树(连n-1条边,且它们的权值和最小)”。

#include <bits/stdc++.h>
using namespace std;
const int N=110,M=1e4+10;
int n,m,k,cnt,val,sum,pre[N];
struct node
{
    int x,y,val;
}p[M<<1];
bool cmp(node a,node b)
{return a.val<b.val;}
int find(int x)
{
    if(pre[x]!=x)pre[x]=find(pre[x]);
    return pre[x];
}
void join(int a,int b)
{pre[find(a)]=find(b);}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        pre[i]=i;
    for(int i=1;i<=m;i++)
    {
        cin>>p[i].x>>p[i].y>>p[i].val;
        sum=sum+p[i].val;
    }
    sort(p+1,p+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(p[i].x)!=find(p[i].y))
        {
            cnt++;
            join(p[i].x,p[i].y);
            val=val+p[i].val;
        }
        if(cnt==n-1)break;
    }
    printf("%d\n",sum-val);
    return 0;
}