暑期个人赛--第六场--A

时间限制 3000 ms  内存限制 65536 KB

题目描述

小弱的学校很喜欢修路,现在给你一张他学校的地图,地图上有n个点和m条双向边,每条边代表一条路,这条路有可能是畅通,也有可能正在修路。大家都知道修路使得交通很不方便。所有小弱很想学校快快的把路修好,使得他能够很轻松的到达主楼915去刷题。但考虑到学校的施工能力有限,小弱想让你帮他算出学校需要集中力量马上修好的最少路数,使得他能够从学校任意点出发,在不经过正在施工的路下到达主楼(编号为1)。

输入格式

有多组数据。
每组数据以n( 1<=n<=10000), m(1<=m<=200000)开头。接下来一行有m行数。每行有三个数,对应于u, v, s,分别为这条路的两端点(编号从1到n)和路况,s = 0代表畅通, s = 1 代表正在修路。输入保证图是连通图。

 

输出格式

对每组数据输出对应的最少路数。

输入样例

3 2
1 2 0
1 3 1
3 2
1 2 0
1 3 0
3 2
1 2 1
1 3 1

输出样例

1
0
2

赛中提交:WA WA WA WA WA WA WA WA 

赛后AC:Y


题目大意:

有n个点和m条无向边,每条边有一个权值,权值只有0和1两种

要求找出从所有点到达一号点的,经过最少权值为1的边的,路径中权值为1的边的个数


反省:

赛中WA了那么多次,首先是因为一开始想错了思路,先用最短路做了几遍,

之后便用正确的方法——最小生成树做了,但是首先用了prim...超内存了

于是改成了kruskal算法,因为这个算法用的是临街链表,所以不会超内存

总的来说

(1)对这几个算法都比较生疏,不能够灵活修改存储边点关系的方式

(2)不能够根据这几个算法的特点快速依据题目做出选择


思路:

裸的最小生成树kruskal算法


其实我怀疑用BELLMANFORD的最短路算法也可以算

对于每一个点他会优先选择权值为0的边,

而在BFM算法里面我们松弛的是当前考察点到达目标点的最短距离

但是我们可以再松弛最短距离的时候再松弛一个当前点到其前驱点的距离,也就是边权

最后再将所有这样的边权加起来,就可以得到最少的需要变为0的边的个数

有空在重新做做吧


下面是AC代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxm 200005
#define maxn 10005
#define INF 999999999

using namespace std;
int fa[maxn];
int r[maxn];
struct edge{
    int u,v,cost;
    edge(){
        cost=0;
    }
};
bool cmp(const edge& e1,const edge& e2)
{
    return e1.cost<e2.cost;
}
edge es[maxm];
int n,m;

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

void init(int n)
{
    for(int i=1;i<=n;i+=1){
        fa[i]=i;
        r[i]=0;
    }
}

void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y){
        return ;
    }

    if(r[x]<r[y]){
        fa[x]=y;
    }
    else{
        fa[y]=x;
        if(r[x]==r[y]){
            r[x]+=1;
        }
    }
}

int kru()
{
    sort(es,es+m,cmp);
    init(n);
    int res=0;
    for(int i=0;i<m;i+=1){
        edge e=es[i];
        if(find(e.u)!=find(e.v)){
            unite(e.u,e.v);
            res+=e.cost;
        }
    }

    return res;
}

int main()
{
    while(scanf("%d %d",&n,&m)!=EOF){
        for(int i=0;i<m;i+=1){
            scanf("%d %d %d",&es[i].u,&es[i].v,&es[i].cost);
        }

        int res=0;
        printf("%d\n",kru());
    }

    return 0;
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值