2018 百度之星 1006 最小生成树

http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=820&pid=1006

 

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

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

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

Input

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

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

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

接下来 mmm 行,每行包含三个整数 a,b,wa,b,wa,b,w 和一个字符 ccc,表示有一条连接点 aaa 与点 bbb 的权值为 www、颜色为 ccc 的无向边。

保证 1≤T≤1001 \leq T \leq 1001T100,1≤n,m≤1001 \leq n,m \leq 1001n,m100,1≤a,b≤n1 \leq a,b \leq n1a,bn,1≤w≤10001 \leq w \leq 10001w1000,c∈{R,G,B}c \in {R,G,B}c{R,G,B},这里 R,G,BR,G,BR,G,B 分别表示红色、绿色和蓝色。

Output

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

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




题意:中文题不解释

思路:建立两个图(红绿和蓝绿)开始求各自最小生成树 小于n-1条边输出-1(因为无法全部遍历) 等于n-1输出两个图跑最小生成树的最小值 大于n-1输出两个图分别跑最小生成树后剩下的边从小到大加
进最小生成树的边然后还是要比较输出两个图的最小值(这个点没考虑到导致wa了n遍,,,说多了都是泪

代码(很多不必要的操作,但是只是为了AC):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define maxn 50010
using namespace std;
int par[maxn];
int ranke[maxn];
int vis[maxn],vis2[maxn];
int used1[maxn],used2[maxn];
int op1[maxn],op2[maxn];
void init(int n)
{
    for(int i=0;i<n;i++){
        par[i]=i;
        ranke[i]=0;
    }


}
int find(int x)//找父亲
{
    if(par[x]==x)return x;
    else {
        return par[x]=find(par[x]);//递归找父亲(因为父亲是统一的)
    }
}
void unite(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x==y)return ;
    if(ranke[x]<ranke[y])
    {
        par[x]=y;
    }
    else par[y]=x;
    if(ranke[x]==ranke[y])ranke[x]++;
}
bool same(int x,int y)
{
    return find(x)==find(y);
}


struct edge{
  int from,to,cost;
};
bool comp(const edge& e1,const edge& e2)
{
    return e1.cost<e2.cost;
}
edge mp[maxn],mp2[maxn];
int V,E,k1,k2;
int res,res2;
int flag,flag2;
char col,cha;
int kruskal()
{
    flag=1;
      memset(used1,0,sizeof(used1));
    sort(mp,mp+k1,comp);
    init(V);
    res=0;
    for(int i=0;i<k1;i++)
    {
        edge s=mp[i];
        //cout<<s.from<<s.to<<endl;
        if(!same(s.from,s.to)){
            unite(s.from,s.to);
         flag++;
        res+=s.cost;
         used1[s.cost]++;
        }
    }
    return res;
}
int kruskal2()
{
    flag2=1;
    memset(used2,0,sizeof(used2));
    sort(mp2,mp2+k2,comp);
    init(V);
    res2=0;
    for(int i=0;i<k2;i++)
    {
        edge s=mp2[i];
        if(!same(s.from,s.to)){
            unite(s.from,s.to);
        flag2++;
        res2+=s.cost;
        used2[s.cost]++;
        }
    }
    return res2;
}
int main()
{
    int t;
    cin>>t;
    for(int z=1;z<=t;z++){
    int d1,d2,dis;
    int mon;
      cin>>V>>E;
       k1=0;
       k2=0;
       for(int i=0,j=0,jj=0;i<E;i++)
       {
           cin>>d1>>d2>>dis;
           scanf("%c%c",&cha,&col);
           vis[j++]=dis;
           vis2[jj++]=dis;
           d1--;
           d2--;
            if(col=='G'||col=='B')
           {
              mp2[k2].from=d1;
              mp2[k2].to=d2;
              mp2[k2].cost=dis;
              k2++;
           }
           if(col=='G'||col=='R'){
            mp[k1].from=d1;
            mp[k1].to=d2;
            mp[k1].cost=dis;
            k1++;
           }
       }
       //cout<<k2<<endl;
       cout<<"Case #"<<z<<":"<<endl;
       if(V==1){
        sort(vis,vis+E);
        int sum=0;
       for(int i=0;i<E;i++)
       {
           sum+=vis[i];
           cout<<sum<<endl;
       }
       }
       else {
       int ans1=kruskal();
        int ans2=kruskal2();
        //cout<<ans1<<endl;
        //cout<<flag2<<endl;
        int oo=0;
        if(flag!=V&&flag2!=V)
        {
            for(int i=0;i<E;i++){cout<<"-1"<<endl;oo=1;}
        }
        else if(flag!=V)  ans1=1000000000;
        else if(flag2!=V) ans2=1000000000;
        int num=0;
        if(oo==1)continue;
        for(int x=0;x<V-1-1;x++){
            op1[x]=-1;
            op2[x]=-1;
        }
       op1[V-2]=ans1;
       op2[V-2]=ans2;
          sort(vis,vis+E);
          for(int i=0;i<E;i++)
            {
               if(used1[vis[i]]!=0){used1[vis[i]]--;vis[i]=1000000000;}
            }
           sort(vis,vis+E);
          int m=0;
          for(int ss=V-1;ss<E;ss++)
          {
                   op1[ss]=op1[ss-1]+vis[m++];
          }
            sort(vis2,vis2+E);
            for(int i=0;i<E;i++)
            {
               // cout<<used2[vis[i]];
               if(used2[vis2[i]]!=0){used2[vis2[i]]--;vis2[i]=1000000;}
            }
           sort(vis2,vis2+E);
          // for(int i=0;i<E;i++)cout<<vis[i]<<endl;
           m=0;
          for(int ss=V-1;ss<E;ss++)
          {
              op2[ss]=op2[ss-1]+vis2[m++];
          }
        for(int i=0;i<E;i++)
        cout<<min(op1[i],op2[i])<<endl;
       }
//        if(flag!=V)cout<<"No"<<endl;
//       else
//       {
//           if(res>mon)cout<<"No"<<endl;
//           else cout<<"Yes"<<endl;
//       }
    }
    return 0;
}

 

posted @ 2018-08-07 16:14  姿态H  阅读(249)  评论(0编辑  收藏  举报