HDU 6349 三原色图 最小生成树

度度熊有一张 nn 个点 mm 条边的无向图,所有点按照 1,2,⋯,n1,2,⋯,n 标号,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。

现在度度熊想选出恰好 kk 条边,满足只用这 kk 条边之中的红色边和绿色边就能使 nn 个点之间两两连通,或者只用这 kk 条边之中的蓝色边和绿色边就能使 nn 个点之间两两连通,这里两个点连通是指从一个点出发沿着边可以走到另一个点。

对于每个 k=1,2,⋯,mk=1,2,⋯,m ,你都需要帮度度熊计算选出恰好 kk 条满足条件的边的权值之和的最小值。

Input

第一行包含一个正整数 TT ,表示有 TT 组测试数据。

接下来依次描述 TT 组测试数据。对于每组测试数据:

第一行包含两个整数 nn 和 mm ,表示图的点数和边数。

接下来 mm 行,每行包含三个整数 a,b,wa,b,w 和一个字符 cc ,表示有一条连接点 aa 与点 bb 的权值为 ww 、颜色为 cc 的无向边。

保证 1≤T≤1001≤T≤100 ,1≤n,m≤1001≤n,m≤100 ,1≤a,b≤n1≤a,b≤n ,1≤w≤10001≤w≤1000 ,c∈{R,G,B}c∈{R,G,B} ,这里 R,G,BR,G,B 分别表示红色、绿色和蓝色。

Output

对于每组测试数据,先输出一行信息 "Case #x:"(不含引号),其中 x 表示这是第 xx 组测试数据,接下来 mm 行,每行包含一个整数,第 ii 行的整数表示选出恰好 ii 条满足条件的边的权值之和的最小值,如果不存在合法方案,输出 −1−1 ,行末不要有多余空格。

Sample Input

1
5 8
1 5 1 R
2 1 2 R
5 4 5 R
4 5 3 G
1 3 3 G
4 3 5 G
5 4 1 B
1 2 2 B

Sample Output

Case #1:
-1
-1
-1
9
10
12
17
22

当时想了一下,决定就用最简单粗暴的方法,直接建两个一模一样的图,然后根据题目要求分别求他们的最小生成树。

然后进行比较。。。

虽然比较蠢,但是也比较好理解哈。。。

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=105;
int t;
int n,m;
struct edge
{
    int s,e;
    int len;
    char c[2];
};
int a1[maxn];
int a2[maxn];
edge e1[maxn];
edge e2[maxn];
int is1[maxn],is2[maxn];
int re1[maxn],re2[maxn];
//找父节点
int finds (int x,int *a)
{
    if(x==a[x])
        return x;
    return a[x]=finds(a[x],a);
}
//合并
bool unit (int x,int y,int *a)
{
    int parx=finds(x,a);
    int pary=finds(y,a);
    if(parx!=pary)
    {
        a[parx]=pary;
        return true;
    }
    return false;
}
//初始化
void init ()
{
   memset (is2,0,sizeof(is2));
   memset (is1,0,sizeof(is1));
   memset (re1,-1,sizeof(re1));
   memset (re2,-1,sizeof(re2));
   for (int i=1;i<=n;i++)
       a2[i]=a1[i]=i;
}
int compare (edge a,edge b)
{
    return a.len<b.len;
}
//kursal算法
void kual(edge *e,int *a,int *is,int *re,char clo)
{
    sort (e,e+m,compare);
    int cc=n;
    int d=0,sum=0;
    for (int i=0;i<m&&cc>1;i++)
    {
        if(e[i].c[0]==clo)
            continue;
        if(unit(e[i].s,e[i].e,a))
        {
            cc--;
            d++;
            is[i]=1;
            sum+=e[i].len;
        }
    }
    //说明无法组成连通图
    if(cc>1)
    {
        return ;
    }
    //将未加入最小生成树的点按从小到大的顺序依次加入集合中
    re[d++]=sum;
    for (int i=0;i<m;i++)
    {
        if(!is[i])
        {
            re[d]=re[d-1]+e[i].len;
            d++;
            is[i]=1;
        }
    }

}
int main()
{
    scanf("%d",&t);
    for (int j=1;j<=t;j++)
    {
        scanf("%d%d",&n,&m);
        init();
        for (int i=0;i<m;i++)
        {
            scanf("%d%d%d%s",&e1[i].s,&e1[i].e,&e1[i].len,e1[i].c);
            e2[i]=e1[i];
        }
        //调用两次kursal算法
        kual(e1,a1,is1,re1,'B');
        kual(e2,a2,is2,re2,'R');
        printf("Case #%d:\n",j);
        for (int i=1;i<=m;i++)
        {
            //三种情况分别讨论
            if(re1[i]!=-1&&re2[i]!=-1)
            printf("%d\n",min(re1[i],re2[i]));
            else if(re1[i]==-1)
                printf("%d\n",re2[i]);
            else if(re2[i]==-1)
                printf("%d\n",re1[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41410799/article/details/81916438