【2018百度之星资格赛】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 条满足条件的边的权值之和的最小值。

分析

好吧我真的是太太太太无聊了,因为发现写正在比赛的题的博客会让人气增加好多哈哈哈哈哈那我就再贴一篇

这个题就是拿并查集和最小生成树瞎搞一下。

分别求出两种情况的最小生成树(情况一只用红色和绿色的边,第二种情况只用绿色和蓝色的边),然后记录一下对于每种情况用了哪些边,当k>n-1的时候按照边权从小打到找没有被用过的边然后加上就可以惹

 下面是代码,写的很丑

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 
  7 using namespace std;
  8 const int INF=2147000000;
  9 const int maxn=1000;
 10 struct Edge{
 11     int from,to,w;
 12     char c;
 13     bool operator<(const Edge& rhs)const{
 14         return w<rhs.w;
 15     }
 16 }edges[maxn];
 17 int T,n,m;
 18 int p[maxn];
 19 int find(int x){
 20     return p[x]==x?x:p[x]=find(p[x]);
 21 }
 22 int vis[3][maxn];
 23 int solve(int s){
 24     memset(vis[s],0,sizeof(vis[s]));
 25     int res=0;
 26     for(int i=1;i<=n;i++)p[i]=i;
 27     for(int i=1;i<=m;i++){
 28         if(s==1&&edges[i].c=='B')
 29             continue;
 30         if(s==2&&edges[i].c=='R')
 31             continue;
 32         int x=find(edges[i].from),y=find(edges[i].to);
 33         if(x!=y){
 34             p[x]=y;
 35             res+=edges[i].w;
 36             vis[s][i]=1;
 37         }
 38     }
 39     int foot=find(1);
 40     for(int i=2;i<=n;i++){
 41         if(foot!=find(i))
 42             return -1;
 43     }
 44     return res;
 45 }
 46 int ans1[maxn],ans2[maxn];
 47 int main(){
 48     scanf("%d",&T);
 49     for(int t=1;t<=T;t++){
 50         memset(ans1,-1,sizeof(ans1));
 51         memset(ans2,-1,sizeof(ans2));
 52         printf("Case #%d:\n",t);
 53         scanf("%d%d",&n,&m);
 54         for(int i=1;i<=m;i++){
 55             scanf("%d%d%d %c",&edges[i].from,&edges[i].to,&edges[i].w,&edges[i].c);
 56         }
 57         sort(edges+1,edges+1+m);
 58         for(int i=1;i<n-1;i++)
 59             printf("-1\n");
 60         int flag=0;
 61         int res1=solve(1);
 62         int res2=solve(2);
 63         if(res1==-1&&res2==-1){
 64             for(int i=n-1;i<=m;i++){
 65                 printf("-1\n");
 66             }
 67             continue;
 68         }
 69         //printf("%d %d\n",res1,res2);
 70         int num=n-1;
 71         if(res1==-1){
 72             ans2[num]=res2;
 73             ans1[num]=INF;
 74 
 75         }
 76         else if(res2==-1){
 77             ans1[num]=res1;
 78             ans2[num]=INF;
 79         }
 80         else{
 81             ans1[num]=res1;
 82             ans2[num]=res2;
 83         }
 84         if(res1!=-1){
 85             for(int i=1;i<=m;i++){
 86                 if(!vis[1][i]){
 87                     num++;
 88                     ans1[num]=ans1[num-1]+edges[i].w;
 89                 }
 90             }
 91         }
 92         else
 93             for(int i=n;i<=m;i++)ans1[i]=INF;
 94 
 95         num=n-1;
 96         if(res2!=-1){
 97             for(int i=1;i<=m;i++){
 98                 if(!vis[2][i]){
 99                     num++;
100                     ans2[num]=ans2[num-1]+edges[i].w;
101                 }
102             }
103         }
104         else
105             for(int i=n;i<=m;i++)ans2[i]=INF;
106         for(int i=n-1;i<=m;i++){
107                 printf("%d\n",min(ans1[i],ans2[i]));
108         }
109     }
110 return 0;
111 }
View Code

猜你喜欢

转载自www.cnblogs.com/LQLlulu/p/9419664.html