P3623 免费道路 - Kruskal

P3623 免费道路 - Kruskal

P3623 免费道路

题意

给定无向图及其权值 \(0/1\),求权值和为 \(n-k-1\) 的生成树。

思路

令鹅卵石为 \(1\),则为求权值和为 \(k\) 的生成树。分类讨论后易得有些权值为一的边不能不放,他们关乎图的联通性。所以我们先求出这些边,即先作一遍边权为 \(0\) 的生成树,然后求出必须的权为 \(1\) 的边。

然后的权为 \(1\) 的边就可一随意摆放,即在必须的 \(1\) 填上后,再将边权和填到 \(k\),最后用 \(0\) 边保证图联通。

无解的情况:

  1. 边权和小于 \(k\)
  2. 边权和等于 \(k\),但图不连通。
  3. 边权和大于 \(k\),但图连通。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 2e4+10;
constexpr int maxm = 1e5+10;
constexpr int INF = 0x3f3f3f3f3f3f3f3f;

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

int n,m,k;
edge edges1[maxm];// erluan shi
edge edges0[maxm];// shuini
int id0,id1,idx;
edge need[maxn];

int fa[maxn];

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

int finr(int x)
{
    return fa[x]==x ? x : fa[x]=finr(fa[x]);
}

bool kruskal1()// 找出必须的鹅卵石路
{
    init();
    int cnt=0;
    for(int i=1;i<=id0;++i)
    {
        int xr=finr(edges0[i].x);
        int yr=finr(edges0[i].y);
        if(xr!=yr)
        {
            ++cnt;
            fa[xr]=yr;
        }
        if(cnt>=n-1)
        {
            break;
        }
    }
    for(int i=1;i<=id1;++i)
    {
        int xr=finr(edges1[i].x);
        int yr=finr(edges1[i].y);
        if(xr!=yr)
        {
            ++cnt;
            fa[xr]=yr;
            need[++idx]=edges1[i];
            edges1[i].w=-1;
        }
        if(cnt>=n-1)
        {
            break;
        }
    }
    if(cnt<n-1 || idx>k)
    {
        return 0;
    }
    return 1;
}

bool kruskal2()
{
    init();
    int cnt1=0;
    int cnt=0;
    for(int i=1;i<=idx;++i)
    {
        int xr=finr(need[i].x);
        int yr=finr(need[i].y);
        if(xr!=yr)
        {
            ++cnt1;
            ++cnt;
            fa[xr]=yr;
        }
    }
    for(int i=1;i<=id1 && cnt1<k;++i)
    {
        if(edges1[i].w==-1)
        {
            continue;
        }
        int xr=finr(edges1[i].x);
        int yr=finr(edges1[i].y);
        if(xr!=yr)
        {
            ++cnt1;
            ++cnt;
            fa[xr]=yr;
            need[++idx]=edges1[i];
        }
    }
    for(int i=1;i<=id0;++i)
    {
        int xr=finr(edges0[i].x);
        int yr=finr(edges0[i].y);
        if(xr!=yr)
        {
            ++cnt;
            fa[xr]=yr;
            need[++idx]=edges0[i];
        }
        if(cnt>=n-1)
        {
            break;
        }
    }
    if(cnt!=n-1 || cnt1!=k)
    {
        return 0;
    }
    return 1;
}

signed main()
{
    #ifndef ONLINE_JUDGE
    freopen("cjdl.in","r",stdin);
    freopen("cjdl.out","w",stdout);
    #endif // ONLINE_JUDGE

    scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1,x,y,w ;i<=m;++i)
    {
        scanf("%lld%lld%lld",&x,&y,&w);
        if(w)
        {
            edges0[++id0]={x,y,0};
        }
        else
        {
            edges1[++id1]={x,y,1};
        }
    }

    if(!kruskal1())
    {
        printf("no solution\n");
        return 0;
    }
    if(!kruskal2())
    {
        printf("no solution\n");
        return 0;
    }
    else
    {
        for(int i=1;i<=idx;++i)
        {
            printf("%lld %lld %lld\n",need[i].x,need[i].y,need[i].w^1);
        }
    }

    return 0;
}
posted @ 2025-11-10 15:14  玖玮  阅读(0)  评论(0)    收藏  举报