3624: [Apio2008]免费道路
Time Limit: 2 Sec Memory Limit: 128 MBSec Special Judge
Submit: 354 Solved: 159
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
题解:
并查集。
其实是要求一种比较奇怪的生成树,首先先做一遍生成树,尽量加1类边,做完后得到的0类边就是这个生成树的必须要加的0类边,判断一下是否有解,然后做生成树,先加上这些必须加的0类边,然后再选0类边直到选完k条后再选1类边直到联通就好了。
Code:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 20100
#define M 100100
struct Edge{
int u,v,p;
}e[M],E[N];
int n,m,K,num=0,s[2],fa[N];
bool vis[M]={0};
int in(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int find(int x){
if (fa[x]==x) return x;
fa[x]=find(fa[x]);
return fa[x];
}
void init(){
s[0]=s[1]=0;
for (int t=1; t>=0; t--){
for (int i=1; i<=m; i++)
if (e[i].p==t){
int f1=find(e[i].u),f2=find(e[i].v);
if (f1!=f2)
fa[f1]=f2,vis[i]=1,s[t]++;
}
}
}
int main(){
n=in(),m=in(),K=in();
for (int i=1; i<=m; i++)
e[i].u=in(),e[i].v=in(),e[i].p=in();
for (int i=1; i<=n; i++) fa[i]=i;
init();
if (s[0]+s[1]!=n-1 || s[0]>K){
printf("no solution\n");
return 0;
}
s[0]=s[1]=0;
for (int i=1; i<=n; i++) fa[i]=i;
for (int i=1; i<=m; i++)
if (!e[i].p && vis[i]){
int f1=find(e[i].u),f2=find(e[i].v);
if (f1!=f2)
fa[f1]=f2,s[0]++,E[++num]=e[i];
}
for (int i=1; i<=m; i++)
if (!e[i].p && s[0]<K){
int f1=find(e[i].u),f2=find(e[i].v);
if (f1!=f2)
fa[f1]=f2,s[0]++,E[++num]=e[i];
}
for (int i=1; i<=m; i++)
if (e[i].p){
int f1=find(e[i].u),f2=find(e[i].v);
if (f1!=f2)
fa[f1]=f2,s[1]++,E[++num]=e[i];
}
if (s[0]<K){
printf("no solution\n");
return 0;
}
for (int i=1; i<=num; i++)
printf("%d %d %d\n",E[i].u,E[i].v,E[i].p);
return 0;
}