BZOJ 3624 免费道路

第一反应:这不先0后1做并查集就行了吗?

然后WA了。。。

哦。。。。啊?哦。。。233

如果按顺序做并查集,有些0的边可能很重要(只能由它作为0连起两个联通块),但并没有被选。

于是先按1做并查集,选出这些边,再按0,1做并查集。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxv 20050
#define maxe 100500
using namespace std;
int n,m,k,x,y,z,cnt0=0,cnt1=0,fath[maxv];
struct edge
{
    int u,v;
}e0[maxe],e1[maxe];
bool vis[maxe],vis0[maxe],vis1[maxe];
void reset()
{
    for (int i=1;i<=n;i++)
        fath[i]=i;
}
int getfather(int x)
{
    if (x!=fath[x])
        fath[x]=getfather(fath[x]);
    return fath[x];
}
void focus()
{
    reset();
    for (int i=1;i<=cnt1;i++)
    {
        int u=e1[i].u,v=e1[i].v;
        int f1=getfather(u),f2=getfather(v);
        if (f1!=f2) fath[f1]=f2;
    }
    for (int i=1;i<=cnt0;i++)
    {
        int u=e0[i].u,v=e0[i].v;
        int f1=getfather(u),f2=getfather(v);
        if (f1!=f2) vis[i]=true;
    }
}
bool kruskal()
{
    reset();
    int ret=0;
    for (int i=1;i<=cnt0;i++)
    {
        if (vis[i])
        {
            int u=e0[i].u,v=e0[i].v;
            int f1=getfather(u),f2=getfather(v);
            if ((f1!=f2) && (ret<k))
            {
                ret++;vis0[i]=true;
                fath[f1]=f2;
            }
        }
    }
    for (int i=1;i<=cnt0;i++)
    {
        if (!vis[i])
        {
            int u=e0[i].u,v=e0[i].v;
            int f1=getfather(u),f2=getfather(v);
            if ((f1!=f2) && (ret<k))
            {
                ret++;vis0[i]=true;
                fath[f1]=f2;
            }
        }
    }
    if (ret!=k) return false;
    for (int i=1;i<=cnt1;i++)
    {
        int u=e1[i].u,v=e1[i].v;
        int f1=getfather(u),f2=getfather(v);
        if (f1!=f2)
        {
            fath[f1]=f2;
            ret++;vis1[i]=true;
        }
    }
    if (ret!=n-1) return false;
    return true;
}
void print_e()
{
    for (int i=1;i<=cnt0;i++)
    {
        if (vis0[i])
            printf("%d %d 0\n",e0[i].u,e0[i].v);
    }
    for (int i=1;i<=cnt1;i++)
    {
        if (vis1[i])
            printf("%d %d 1\n",e1[i].u,e1[i].v);
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if (!z)
        {
            cnt0++;
            e0[cnt0].u=x;e0[cnt0].v=y;
        }
        else
        {
            cnt1++;
            e1[cnt1].u=x;e1[cnt1].v=y;
        }
    }
    focus();
    if (!kruskal()) printf("no solution\n");
    else print_e();
    return 0;
}
时间: 2024-10-18 10:52:41

BZOJ 3624 免费道路的相关文章

bzoj 3624: [Apio2008]免费道路 生成树的构造

3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 111  Solved: 49[Submit][Status] Description Input Output Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 1 还是看的网上的标

3624: [Apio2008]免费道路

3624: [Apio2008]免费道路 https://www.lydsy.com/JudgeOnline/problem.php?id=3624 题意: 一张无向图,每种边有两种类型0和1.求一个最小生成树使得有k条0边. 分析: 为了满足有k条0边的限制,先考虑0边哪些必选,如果所有1边都加入后,还有0边可以使得图不连通,那么这些0边必须选. 把必须选的加上然后再加到k,然后再加1边.中间判一下是否必选的大于k,0边是否大于等于k. 代码: 1 #include<bits/stdc++.h

[Apio2008]免费道路[Kruscal]

3624: [Apio2008]免费道路 Time Limit: 2 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 1292  Solved: 518[Submit][Status][Discuss] Description Input Output Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2

[APIO2008]免费道路

# [APIO2008]免费道路 ### 第一反应 考虑朴素的克鲁斯卡尔算法加一个限制,先选鹅卵石路,且选到k个就停止 带来的问题: - ~~叶子节点特殊处理,都选上~~(但其实是连通性) - ~~而且你诡异的发现,tm,这个鹅卵石路可以突破最小生成树!!!~~(不仔细看题面的后果) ### 正解 考虑上文中的连通性,先用水泥路跑一遍$Kruskal$,然后不连通的且用到鹅卵石路的都要选上.剩下的既然水泥路可以,那么鹅卵石路也可以代替嘛,先选鹅卵石路,选到$k$个就停止 emm,那么什么时候是无

BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]

题意: 一张图0,1两种边,构造一个恰有k条0边的生成树 优先选择1边构造生成树,看看0边是否小于k 然后保留这些0边,补齐k条,再加1边一定能构成生成树 类似kruskal的证明 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=2e4+5, M=1e5+5; typedef long

bzoj3624: [Apio2008]免费道路

具体题目:https://vjudge.net/problem/HYSBZ-3624 Description 一个王国有N个城市和M条无向道路,这M条道路中有一些是鹅卵石路一些是水泥路.现在国王要选择尽可能少的路免费,并且使每两个城市都有一条免费路径.国王打算保留刚好K条鹅卵石路.请问国王是否可以办到所有这些要求,如果能则输出路径的两个城市和路的种类,否则"no solution". HINTN <= 20000M <= 100000 Analysis如果能成功肯定是最小生

bzoj 3575: [Hnoi2014]道路堵塞

Description A 国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所有从城市1到城市N的路径中最短的.不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞. 现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少. Input 输入文件第一行是三个用空格分开的正整数N.M和L,分别表示城市数目.单向道路数目

【bzoj3624】Apio2008—免费道路

http://www.lydsy.com/JudgeOnline/problem.php?id=3624 (题目链接) 题意 给出一张无向图,其中有0类边和1类边.问能否构成正好有K条0类边的生成树,并输出方案. Solution 先将所有1类边加入生成树,然后再加入0类边,那么现在加入的0类边就是必须加入的0类边,将它们打上标记.然后再将并查集初始化,继续加0类边直到数量达到K,最后加1类边. 代码 // bzoj3624 #include<algorithm> #include<io

bzoj 2435: [Noi2011]道路修建 树上 dp

2435: [Noi2011]道路修建 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2435 Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘