zoukankan      html  css  js  c++  java
  • 2018"百度之星"程序设计大赛

    problem

    • 给一张n个点m条边的有向图,每条边有一个正整数权值以及一种色光三原色红、绿、蓝之一的颜色。
    • 恰好选出k条边,满足只用这k条边之中的红色边和绿色边(或者蓝色边和绿色边)就能使n个点之间两两连通
    • 对于k==1…m,计算选出恰好k条满足条件的边的权值之和的最小值。

    solution

    • 当 k < n-1 时,分别求两种情况的最小生成树(红绿,蓝绿),记录每种情况用了哪些边。
    • 当 k > n-1 时,按照边权从小到大找没有用过的直接加

    codes

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn = 1100, inf=2147000000;
    
    //Grape
    int n, m;
    struct Edge{ int u, v, w; char c; }e[maxn];
    bool cmp(Edge a, Edge b){return a.w<b.w;}
    
    //UnionFindSet
    int fa[maxn];
    void init(int _n){for(int i = 1; i <= _n; i++)fa[i]=i;}
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void merge(int x, int y){x=find(x),y=find(y);fa[x]=y;}
    
    //MST
    int vis[3][maxn];//记录边
    int solve(int s){
        memset(vis[s],0,sizeof(vis[s]));
        int mst = 0;
        init(n);
        for(int i = 1; i <= m; i++){
            if(s==1&&e[i].c=='B')continue;
            if(s==2&&e[i].c=='R')continue;
            int x = find(e[i].u), y = find(e[i].v);
            if(x != y){
                merge(x,y);
                mst += e[i].w;
                vis[s][i] = 1;
            }
        }
        for(int i = 2; i <= n; i++)//判断是否联通
            if(find(i)!=find(1))return -1;
        return mst;
    }
    
    //Timu
    int ans1[maxn], ans2[maxn];
    
    int main(){
        int w;  scanf("%d",&w);
        for(int _w = 1; _w <= w; _w++){
            printf("Case #%d:
    ", _w);
            memset(ans1,-1,sizeof(ans1));
            memset(ans2,-1,sizeof(ans2));
    
            scanf("%d%d",&n,&m);
            for(int i = 1; i <= m; i++)
                scanf("%d%d%d %c",&e[i].u,&e[i].v,&e[i].w,&e[i].c);
            sort(e+1,e+m+1,cmp);
    
            for(int i = 1; i < n-1; i++)
                printf("-1
    ");
            int mst1 = solve(1);
            int mst2 = solve(2);
            if(mst1==-1&&mst2==-1){//森林,无法联通
                for(int i = n; i <= m; i++)
                    printf("-1
    ");
                continue;
            }
            int cur = n-1;
            if(mst1==-1){//赋初始值
                ans1[cur] = inf;
                ans2[cur] = mst2;
            }else if(mst2==-1){
                ans1[cur] = mst1;
                ans2[cur] = inf;
            }else{
                ans1[cur] = mst1;
                ans2[cur] = mst2;
            }
            if(mst1!=-1){
                for(int i = 1; i <= m; i++)
                    if(!vis[1][i]){cur++;ans1[cur]=ans1[cur-1]+e[i].w;}
            }else for(int i = n; i <= m; i++)ans1[i] = inf;
            cur = n-1;
            if(mst2!=-1){
                for(int i = 1; i <= m; i++)
                    if(!vis[2][i]){cur++;ans2[cur]=ans2[cur-1]+e[i].w;}
            }else for(int i = n; i <= m; i++)ans2[i] = inf;
    
            for(int i = n-1; i <= m; i++)
                printf("%d
    ",min(ans1[i],ans2[i]));
        }
        return 0;
    }
    
  • 相关阅读:
    JS-两个空数组为什么不相等?
    ES6---箭头函数()=>{} 与function的区别(转载)
    SASS用法指南
    scss/less语法以及在vue项目中的使用(转载)
    基于vue+mint-ui的mobile-h5的项目说明
    vue中mint-ui的filed的与blur事件结合实现检查用户输入是否正确
    Carrierwave 如何配置合理的上传文件名(转自李华顺)
    ruby大神与菜鸟的代码区别
    用imageMagick合成图片添加图片水印
    想做喜欢的安卓应用
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444602.html
Copyright © 2011-2022 走看看