P3623 免费道路 - Kruskal
P3623 免费道路 - Kruskal
题意
给定无向图及其权值 \(0/1\),求权值和为 \(n-k-1\) 的生成树。
思路
令鹅卵石为 \(1\),则为求权值和为 \(k\) 的生成树。分类讨论后易得有些权值为一的边不能不放,他们关乎图的联通性。所以我们先求出这些边,即先作一遍边权为 \(0\) 的生成树,然后求出必须的权为 \(1\) 的边。
然后的权为 \(1\) 的边就可一随意摆放,即在必须的 \(1\) 填上后,再将边权和填到 \(k\),最后用 \(0\) 边保证图联通。
无解的情况:
- 边权和小于 \(k\)。
- 边权和等于 \(k\),但图不连通。
- 边权和大于 \(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;
}

浙公网安备 33010602011771号