3624: [Apio2008]免费道路
Time Limit: 2 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 727 Solved: 300
[ 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
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
4 3 0
5 3 1
1 2 1
HINT
Source
这道题就是求一颗生成树,使特殊边的条数恰好为k 。
那么我们可以把所有非特殊边先加进去,用并查集把所有联通块并在一起,然后开始加特殊边,看是否存在必须加的特殊边(即不加这条边之前这两个点不连通)。
然后我们重新构建生成树,先把所以的必须加的特殊边加进去,然后在加特殊边直到K条,最后再加非特殊边,保证是颗树即可。
注意各种无解的情况,小心处理即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 20003
#define M 100003
using namespace std;
int n,m,k;
int u[M],v[M],c[M];
int cnt,x[M],y[M],fa[N],vis[M],belong[M],x1[M],yy[M],c1[M];
int find(int x)
{
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++)
scanf("%d%d%d",&u[i],&v[i],&c[i]);
for (int i=1;i<=n;i++)
fa[i]=i;
for (int i=1;i<=m;i++)
if (c[i]&&find(u[i])!=find(v[i]))
{
int r1=find(u[i]); int r2=find(v[i]);
fa[r2]=r1;
}
for (int i=1;i<=m;i++)
if (!c[i]&&find(u[i])!=find(v[i]))
{
cnt++; vis[m]=1;
x[cnt]=u[i]; y[cnt]=v[i]; belong[cnt]=c[i];
int r1=find(u[i]); int r2=find(v[i]);
fa[r2]=r1;
}
int t=find(1);
for (int i=2;i<=n;i++)
if (find(i)!=t)
{
printf("no solution\n");
return 0;
}
for (int i=1;i<=n;i++) fa[i]=i;
if (cnt>k) {
printf("no solution\n");
return 0;
}
int num=0; int tot=0;
for (int i=1;i<=cnt;i++)
{
int r1=find(x[i]); int r2=find(y[i]);
fa[r2]=r1;
num++; tot++;
x1[tot]=x[i]; yy[tot]=y[i]; c1[tot]=belong[i];
}
for (int i=1;i<=m;i++)
if (!c[i]&&find(u[i])!=find(v[i]))
{
int r1=find(u[i]); int r2=find(v[i]);
fa[r2]=r1; num++; tot++;
x1[tot]=u[i]; yy[tot]=v[i]; c1[tot]=c[i];
if (tot==k) break;
}
if (tot!=k) {
printf("no solution\n");
return 0;
}
for (int i=1;i<=tot;i++)
printf("%d %d %d\n",x1[i],yy[i],c1[i]);
for (int i=1;i<=m;i++)
if (c[i]&&find(u[i])!=find(v[i]))
{
printf("%d %d %d\n",u[i],v[i],c[i]);
int r1=find(u[i]); int r2=find(v[i]);
fa[r2]=r1; num++;
if (num==n-1) break;
}
}