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;
    }
    
  • 相关阅读:
    VScode 修改中文字体
    missing KW_END at ')' near '<EOF>'
    SQL inner join, join, left join, right join, full outer join
    SQL字符替换函数translater, replace
    SQL COOKBOOK SQL经典实例代码 笔记第一章代码
    sqlcook sql经典实例 emp dept 创建语句
    dateutil 2.5.0 is the minimum required version python
    安装postgresql后找不到服务 postgresql service
    Postgres psql: 致命错误: 角色 "postgres" 不存在
    【西北师大-2108Java】第十六次作业成绩汇总
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444602.html
Copyright © 2011-2022 走看看