首页 > 代码库 > bzoj3624,[Apio2008]免费道路

bzoj3624,[Apio2008]免费道路

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3624

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

题解:

 首先有一些鹅卵石的路是必须选的,那么可以先把马路的做一遍最小生成树,若不连通,则往里面加鹅卵石的路使其连通,这个时候加的边都为必须加的。接着再做一遍最小生成树,先把上一次找出的必加的边加进去,再往里面加鹅卵石的边,使其到达k条,若不连通,加马路,这时选的边加上第一遍必须选的边即为答案

代码解释:

q标记的是这次操作是在找答案还是找必须选的鹅卵石的边。b[]记录的是边有没有选,第一次找必加的边的时候只要记录鹅卵石边有没有加,第二次则需要记录所有的边

代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 20010
#define M 100010
using namespace std;
struct data{int u,v,c;}a[M];
int fa[N],b[M];
int m,x,y,all,sum,q,k,n;
int getint()
{
    int res=0,w=1;
    char ch=getchar();
    while ((ch>9 || ch<0)&&ch!=-) ch=getchar();
    if (ch==-) w=-1,ch=getchar();
    while (ch>=0&&ch<=9) res=res*10+ch-0,ch=getchar();
    return res*w;
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void add(int p)
{
    for (int i=1;i<=m;i++)
        {
            if (a[i].c==p)
                {
                    x=find(a[i].u); y=find(a[i].v);
                    if (x!=y)
                        {
                            all++; fa[x]=fa[y];
                            if (q) b[i]=1;
                            if (!p) {b[i]=1; sum++; if (q&&sum==k) return;}
                        }
                }
        }
}
int main()
{
    n=getint(); m=getint(); k=getint();
    for (int i=1;i<=m;i++)
        a[i].u=getint(),a[i].v=getint(),a[i].c=getint();

    for (int i=1;i<=n;i++) fa[i]=i;
    all=0; add(1); add(0); 
    if (all!=n-1||sum>k) {printf("no solution\n"); return 0;}

    for (int i=1;i<=n;i++) fa[i]=i; sum=0;
    for (int i=1;i<=m;i++)
        if (b[i]) sum++,x=find(a[i].u),y=find(a[i].v),fa[x]=y;
    q=1;
    if (sum!=k) add(0);
    add(1);

    if (sum<k) {printf("no solution\n"); return 0;}
    for (int i=1;i<=m;i++)
        if (b[i]) printf("%d %d %d\n",a[i].u,a[i].v,a[i].c);
    return 0;
}

 

bzoj3624,[Apio2008]免费道路