• 自出题,写题解《招募士兵》


    招募士兵
    (conscription.pas/c/cpp)
    【问题描述】
    小W拥有一个国家,现在他希望建立一支军队来保护他的国家。他选中了N个女孩和M个男孩希望招募他们成为他的士兵。在没有任何先决条件的情况下,他招募一个士兵需要花费10000RMB。现在小W可以利用这些人之间的关系来减少他的花费。如果女孩X和男孩Y存在有一个关系值D(两人之间可能有多个关系值),而且她们之中有一个人被招募了。那么小W可以在招募另一个人的时候减少D的花费(实际10000-D的费用)。
    现在给你这些男孩女孩之间的关系,希望你告诉小W告诉他招募所有人的最少花费。
    注意:招募某一个人时,只能利用一个关系。
    【输入】
    输入文件conscription.in中文件第一行包含三个整数N,M,R。表示N个女孩,M个男孩与R条关系。
    接下来R行,每行包含三个整数Xi,Yi和Di,表示女孩Xi和男孩Yi有Di的关系。
    【输出】
    conscription.out中只有一行一个数,为最小费用。
    【输出样例】
    5 5 8
    4 3 6831
    1 3 4583
    0 0 6592
    0 1 3063
    3 3 4975
    1 3 2049
    4 2 2104
    2 2 781
    【输出样例】
    71071

    【数据说明】
    100%的数据:1<=N, M <=100000,0 <=R <=200,000,0 < di < 10000

    本题烤驴到一个并查集的问题,然后,我们把他可以减少的价钱排个序,再一个一个地去并起来,如果他们的father一样,就不可以并起来,这样子就能解决问题。

    参考程序:

    type
            new=record
                    x:longint;
                    y:longint;
                    r:longint;
                    bz:boolean;
            end;
    
    var
            i,j,k,l,n,m,r,v,x,y:longint;
            ans:int64;
            f:array[0..200000] of longint;
            a:array[1..200000] of new;
            bz:boolean;
    procedure qs(l,r:longint);
    var
            i,j,m:longint;
            t:new;
    begin
            i:=l;
            j:=r;
            m:=a[(l+r) div 2].r;
            repeat
                    while a[i].r>m do inc(i);
                    while a[j].r<m do dec(j);
                    if i<=j then
                    begin
                            t:=a[i];
                            a[i]:=a[j];
                            a[j]:=t;
                            inc(i);
                            dec(j);
                    end;
            until i>j;
            if l<j then qs(l,j);
            if i<r then qs(i,r);
    end;
    function zs(t:longint):longint;
    var
            i,j,k,l:longint;
    begin
            l:=t;
            while f[t]<>t do
            begin
                    t:=f[t];
            end;
            while f[l]<>t do
            begin
                    j:=f[l];
                    f[l]:=t;
                    l:=j;
            end;
            zs:=t;
    
    end;
    
    begin
            readln(n,m,r);
            for i:=1 to r do
            begin
                    readln(a[i].x,a[i].y,a[i].r);
                    a[i].y:=a[i].y+n;
            end;
            for i:=1 to n+m do f[i]:=i;
            qs(1,r);
            ans:=0;
            v:=0;
    
            for i:=1 to r do
            begin
                    if zs(a[i].x)<>zs(a[i].y) then
                    begin
                            x:=zs(a[i].x);
                            y:=zs(a[i].y);
                            f[x]:=y;
                            a[i].bz:=true;
                            ans:=ans+(10000-a[i].r);
                            inc(v);
                    end;
            end;
            writeln(ans+(n+m-v)*10000);
    end.
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    Kostya Keygen#2分析
    一个简单的windows勒索软件分析
    MSRHook与SSDTHook
    VS2013中调驱动
    VMProtect1.63分析
    Linux内核分析总结
    进程的切换和系统的一般执行过程
    可执行程序的装载
    进程的描述和进程的创建
    扒开系统调用的三层皮(下)
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148462.html
Copyright © 2020-2023  润新知