并查集、最小生成树、kruskal算法题目集(入门)

最近acm集训又双叒来了,新学了并查集,来更一贴
先来个模板题!
洛谷 3366 最小生成树

#include 
//时间关系注释写的不是很详细。
using namespace std;

int S[100005];            //并查集
struct Edge{
     int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
     return a.w<b.w;}
int find(int u){
     return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;

int kruskal(){
     

for(int i=1;i<=n;i++)
    S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
     
    int b=find(edge[i].u);
    int c=find(edge[i].v);
    if(b==c)continue;
    S[b]=c;
    num++;
    if(ans<edge[i].w)ans=edge[i].w;
}
return ans;
}
int main()
{
     
    while(~scanf("%d %d",&n,&m)){
     
        for(int i=1;i<=m;i++)
            scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
        printf("%d\n",kruskal());

    }
    return 0;
}

在更一道考察联通的问题,话说在离散数学的上机考试也应该会考到相关算法。
洛谷 1536 村村通
话不多说,直接上代码,其实并查集都一个意思,看懂了就都懂了。

#include 
//和上一个模板题一样的思路
using namespace std;

int S[1005];            //并查集
struct Edge{
     int u,v;}edge[10005];//定义边
int find(int u){
     return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num;

int kruskal(){
     
int ans=0;
for(int i=1;i<=n;i++)
    S[i]=i;

for(int i=1;i<=m;i++){
     
    int b=find(edge[i].u);
    int c=find(edge[i].v);
    if(b==c)continue;
    S[b]=c;
    num++;
}
return n-1-num;
}
int main()
{
     
    while(~scanf("%d %d",&n,&m)){
     
        if(n==0)break;
        num=0;
        for(int i=1;i<=m;i++)
            scanf("%d %d",&edge[i].u,&edge[i].v);
        printf("%d\n",kruskal());
    }
    return 0;
}

继续更一道
洛谷 2820 局域网

#include 
//还是最开始的模板!hhh
using namespace std;

int S[1000];            //并查集
struct Edge{
     int u,v,w;}edge[1005];//定义边
bool cmp(Edge a,Edge b){
     return a.w<b.w;}
int find(int u){
     return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,sum;

int kruskal(){
     
int ans=0;
for(int i=1;i<=n;i++)
    S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
     
    int b=find(edge[i].u);
    int c=find(edge[i].v);
    if(b==c)continue;
    S[b]=c;
    ans+=edge[i].w;
}
return sum-ans;
}
int main()
{
     
    while(~scanf("%d %d",&n,&m)){
     
            sum=0;
        for(int i=1;i<=m;i++){
     
            scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
            sum+=edge[i].w;}
        printf("%d\n",kruskal());
    }
    return 0;
}

以上都是一个模板的,下面更新一道稍难的(虽然官方认定为普及水平),因为要考虑联通分支是否满足,不过想清楚了还是一个并查集!
洛谷 1195 口袋的天空

#include 
//稍有不同,但大致思路一样!
using namespace std;

int S[100005];            //并查集
struct Edge{
     int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
     return a.w<b.w;}
int find(int u){
     return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;

void kruskal(){
     

for(int i=1;i<=n;i++)
    S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
     
    int b=find(edge[i].u);
    int c=find(edge[i].v);
    if(b==c)continue;
    S[b]=c;
    num++;
    ans+=edge[i].w;
    if(num==n-k)return;
}
return ;
}
int main()
{
     
    while(~scanf("%d %d %d",&n,&m,&k)){
     
            num=0;
        for(int i=1;i<=m;i++)
            scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
        kruskal();
    if(num==n-k)
        printf("%d\n",ans);
        else printf("No Answer\n");
    }
    return 0;
}

最后来一道usaco的体验体验
洛谷 1547 [USACO05MAR]Out of Hay S
题目不难,直接上代码!
并查集、最小生成树、kruskal算法题目集(入门)_第1张图片

#include 

using namespace std;

int S[100005];            //并查集
struct Edge{
     int u,v,w;}edge[100005];//定义边
bool cmp(Edge a,Edge b){
     return a.w<b.w;}
int find(int u){
     return S[u]==u?u:find(S[u]);}//查询并查集
int m,n,num,k,ans;

int kruskal(){
     

for(int i=1;i<=n;i++)
    S[i]=i;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++){
     
    int b=find(edge[i].u);
    int c=find(edge[i].v);
    if(b==c)continue;
    S[b]=c;
    num++;
    if(ans<edge[i].w)ans=edge[i].w;
}
return ans;
}
int main()
{
     
    while(~scanf("%d %d",&n,&m)){
     
        for(int i=1;i<=m;i++)
            scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
        printf("%d\n",kruskal());

    }
    return 0;
}

今天先更到这,学校oj上还有几题,到时候做完一起来更新!

你可能感兴趣的:(icpc,图论,程序设计,acm竞赛,序列最小化优化算法)