POJ 1679 浅谈不严格次小生成树

这里写图片描述
世界真的很大
今天狂刷了好多题,算是图论的一个小小阶段总结吧
其他题实在是有点水,算是复习了一下二分图的性质,但主要目的还是练板子
就由这道题(或是下一道,或者下下)来终结图论的复习吧!
毕竟NOIP已经不远了,越来越有要退赛的预感

看题先:

description:

给定一张图,判断其最小生成树是否唯一

input:

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

output:

For each input, if the MST is unique, print the total cost of it, or otherwise print the string ‘Not Unique!’.

参考这道题:BZOJ 1977
然后这道题就是水题了
直接判一下最小生成树链上的最大值有没有等于没有选上的这条边的值的
如果有,那么就说明最小生成树不唯一,反之则唯一
一遍Kruscal,一遍lca搞定
纪念1A

完整代码:

#include<stdio.h>
#include<algorithm>
#include<cstring>
using namespace std;

const int INF=0x3f3f3f3f;

struct edge
{
    int u,v,w,last;
}ed[10010],ad[10010];

int n,m,T,ans=0,bns=INF,tot=0,num=0;
int head[1010],dep[1010],st[1010][20],anc[1010][20];
int fa[1010],used[10010];

void add(int u,int v,int w)
{
    num++;
    ed[num].u=u;
    ed[num].v=v;
    ed[num].w=w;
    ed[num].last=head[u];
    head[u]=num;
}

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

bool cmp(const edge &a,const edge &b)
{
    return a.w<b.w;
}

void Kruscal()
{
    sort(ad+1,ad+m+1,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x=getfather(ad[i].u),y=getfather(ad[i].v);
        if(x!=y)
        {
            tot++,fa[x]=y,ans+=ad[i].w,used[i]=1;
            add(ad[i].u,ad[i].v,ad[i].w),add(ad[i].v,ad[i].u,ad[i].w);
        }
        if(tot==n-1) break ;
    }
}

void dfs(int u,int f)
{
    anc[u][0]=f;
    for(int i=1;i<=18;i++)
        anc[u][i]=anc[anc[u][i-1]][i-1],
        st[u][i]=max(st[u][i-1],st[anc[u][i-1]][i-1]);
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(v==f) continue ;
        dep[v]=dep[u]+1,st[v][0]=ed[i].w;
        dfs(v,u);
    }
}

int lca(int u,int v)
{
    int rt=0;
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=18;i>=0;i--)
        if(dep[anc[u][i]]>=dep[v])
            rt=max(rt,st[u][i]),u=anc[u][i];
    if(u==v) return rt;
    for(int i=18;i>=0;i--)
        if(anc[u][i]!=anc[v][i])
            rt=max(rt,max(st[u][i],st[v][i])),u=anc[u][i],v=anc[v][i];
    return max(rt,max(anc[u][0],anc[v][0]));
}

void init()
{
    memset(head,0,sizeof(head));
    memset(fa,0,sizeof(fa));
    memset(dep,0,sizeof(dep));
    memset(st,0,sizeof(st));
    memset(anc,0,sizeof(anc));
    memset(used,0,sizeof(used));
    num=ans=tot=0;
    bns=INF;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&ad[i].u,&ad[i].v,&ad[i].w);
        Kruscal();
        dfs(1,1);
        for(int i=1;i<=m;i++)
        {
            if(used[i]) continue ;
            int u=ad[i].u,v=ad[i].v;
            bns=min(bns,ad[i].w-lca(u,v));
        }
        if(bns) printf("%d\n",ans);
        else printf("Not Unique!\n");
    }
    return 0;
}
/*
Whoso pulleth out this sword from this stone and anvil is duly born King of all England
*/

嗯,就是这样

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值