xmuOJ 安全网络 ver.3

xmuOJ 安全网络 ver.3

来源

http://acm.xmu.edu.cn/JudgeOnline/problem.php?cid=1023&pid=1

描述

Problem B: 安全网络 ver.3
Time Limit: 2500 MS  Memory Limit: 64 MB
Submit: 691  Solved: 176
[Submit][Status][Web Board]
Description
  现在有个一个内部局域网络,里面有N台机器。为了某种安全原因的考虑,有些机器之间是无法直接通讯的,即使可以通讯,机器与机器之间的通讯都是经过加密的。由于不同机器之间传输的内容不同,所以他们通讯采用的加密级别也不大相同。不同的加密级别导致破解的难度不一样,越高的加密级别破解需要的时间也越多。如果我们获得了编号为i的机器的完全控制权,且机器i和机器j可以直接通讯,另外我们破解了机器i和机器j之间的加密信息,那么我们就得到了机器j的完全控制权。
  现在你通过了某种手段入侵了1号机器,得到了这台机器的完全控制权,为了扩大劳动果实,你准备对其余的机器也在你的控制当中,但是由于需要破解加密信息才能控制其它机器,你又不想浪费太多时间在破解上,现在你来算算你至少需要多少时间才能完全控制整个网络。
Input
  输入的第一行是两个正整数N(2 <= N <= 100,000) M(0 < M <= 200,000),表示机器的数目和允许通讯的机器对数。
  输入的第二行开始到第M+1行,每行3个整数,A B T( 1 <= A, B <= N, T <= 10,000, A ≠ B),表示机器A和机器B之间可以互相通讯,且破解这个通讯的时间是T。输入保证不存在重复的AB对。
Output
  输出完全控制所有机器的最少时间。如果无法满足要求则输出-1。
Sample Input
4 4

1 2 4

1 3 9

2 3 2

4 3 1
 
Sample Output
7

分析

一道求解最小生成树的题目,可用kruscal来解。问题不一定有解,可用变量cnt记录加入最小生成树中的顶点的个数,如果小于N,则无解。

详细讲解 傻子都能看懂的并查集入门

注意点

//函数father(a) 容易写成 father[a],所以还是用 find_fa()比较好
//N M 容易混淆 测试数据一定要让 N!=M
测试数据:
4 6
1 2 4
1 3 9
2 3 2
4 3 1
1 4 7
2 4 3

out:7
//题目要求里的顶点序号从1开始,所以程序中的for语句也应当从1开始
//cnt 应当初始化为1,而不是0
//time 是oj平台预定义变量

代码

运行情况

第一遍超时了
clipboard.png
进行路径压缩的优化后
clipboard.png
优化效果非常明显。

AC代码

#include <iostream>
#include<stdlib.h>
#include <vector>
#include<stdio.h>
#include<string>
#include<queue>
#include<string.h>
#include<algorithm>

using namespace std;


typedef struct edge
{
    int x;
    int y;
    int w;
}edge;

int length = 0;//记录MIT 总权重
int* fa;
int cnt=1; //记录最小生成树中顶点的个数

int cmp(const void* a, const void* b)
{
    return (*(edge*)a).w-(*(edge*)b).w;
}

int father(int x)
{
    return x == fa[x] ? x :fa[x] = father(fa[x]) ;  // fa[x] = father(x) 是为了路径压缩
//  if (fa[x] == x)
//        return x;
//    else
//        return father(fa[x]);
}

int union_set(int a,int b,int w){
    a = father(a);
    b = father(b);
    if(a==b)
        return -1;
    else
    {
       fa[a] = b;
       length+=w;
       cnt++;
       return 1;
    }
}



int main()
{
    int N,M;
    int i,j,k;

     //initialize
    scanf("%d %d", &N,&M);
    fa = (int*)malloc(sizeof(int)*(N+1));
    for (i =1 ; i <=N ; i++)
        fa[i]=i;
    edge* e = (edge*)malloc(sizeof(edge)*(M+1));
    for (i =1 ; i <=M ; i++)
       scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].w);

    qsort(e+1,M,sizeof(edge),cmp);
    //O(|E|log|E|)
     for (i =1 ; i <=M ; i++)
        union_set(e[i].x,e[i].y,e[i].w);


    //output
    if(cnt!=N) //被破译的点没有N个
        cout<<-1<<endl;
    else
    {
        cout<<length<<endl;
    }

    return 0;
}
/*
4 6
1 2 4
1 3 9
2 3 2
4 3 1
1 4 7
2 4 3

out:
*/

//函数father(a) 容易写成 father[a],所以还是用 find_fa()比较好
//N M 容易混淆 测试数据一定要让 N!-M
//题目要求里的顶点序号从1开始,所以程序中的for语句也应当从1开始
//cnt 应当初始化为1,而不是0
//time 是oj平台预定义变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值