2017.2.11【初中部GDKOI】模拟赛B组 T1:最小比例

**【NOIP2013模拟11.6B组】最小比例(ratio) **
Description
图中共有N个点的完全图,每条边都有权值,每个点也有权值。要求选出M个点和M-1条边,构成一棵树,使得:
这里写图片描述
即所有边的权值与所有点的权值之和的比率最小。

给定N和M,以及N个点的权值,和所有的边权,要求M个点的最小比率生成树。

Input

第一行包含两个整数N和M(2<=N<=15,2<=M<=N),表示点数和生成树的点数。

接下来一行N个整数,表示N个点的边权。

最后N行,每行N列,表示完全图中的边权。所有点权和边权都在[1,100]之间。

Output

输出最小比率生成树的M个点。当答案出现多种时,要求输出的第一个点的编号尽量小,第一个相同,则第二个点的编号尽量小,依次类推,中间用空格分开。编号从1开始。

Sample Input

输入1:

3 2

30 20 10

0 6 2

6 0 3

2 3 0

输入2:

2 2

1 1

0 2

2 0

Sample Output

输出1:

1 3

输出2:

1 2

题解:100%
这道题一看就是一道最小生成树的题目。当然,此题要选M个点和M-1条边。然而数据只有15个点,递归每一个点选不选择,时间2^15当然是可以卡过的。然后,我们就在把每个选择的点进行一个最小生成树,连起来,把相应的∑node和∑edge给求出来,在记录就可以过了。
注意:
本题使用的最小生成树可以为克鲁斯卡尔或普利姆做,还是要掌握滴~

标程(克鲁斯卡尔的方法):

type
        new=record
                x:longint;
                y:longint;
                a:longint;
        end;
var
        i,j,k,l,n,m,nodeans,edgeans,ans,dep:longint;
        f,nodejl,node,sans:array[0..100] of longint;
        bz:array[0..1000] of boolean;
        route:array[0..1000] of new;
        map:array[0..100,0..100] of longint;
        ratio:extended;
procedure qs(l,r:longint);
var
        i,j,mid:longint;
        t:new;
begin
        i:=l;
        j:=r;
        mid:=route[(i+j) div 2].a;
        repeat
                while route[i].a<mid do inc(i);
                while route[j].a>mid do dec(j);
                if i<=j then
                begin
                        t:=route[i];
                        route[i]:=route[j];
                        route[j]:=t;
                        inc(i);
                        dec(j)
                end
        until i>j;
        if i<r then qs(i,r);
        if l<j then qs(l,j)
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;
procedure dg(depnode:longint);
var
        i,j,k,l,x,y:longint;
begin
        if ans=m then
        begin
                edgeans:=0;
                for i:=1 to n do f[i]:=i;
                i:=1;
                j:=1;
                while j<=m-1 do
                begin
                        if (bz[route[i].x])and(bz[route[i].y]) then
                        if zs(route[i].x)<>zs(route[i].y) then
                        begin
                                x:=zs(route[i].x);
                                y:=zs(route[i].y);
                                f[x]:=y;
                                inc(edgeans,route[i].a);
                                inc(j);
                        end;
                        inc(i);
                        if i>n*n then exit;
                end;
                if ratio>edgeans/nodeans then
                begin
                        sans:=nodejl;
                        ratio:=edgeans/nodeans;
                end;
                edgeans:=0;
        end
        else
        begin
                for i:=depnode to n do
                begin
                        if (nodejl[1]=1)and(nodejl[2]=4)and(nodejl[3]=6)
                           and(nodejl[4]=11)and(nodejl[5]=12)and(nodejl[6]=13)then
                                nodejl[1]:=1;
                        bz[i]:=true;
                        inc(nodeans,node[i]);
                        inc(ans);
                        nodejl[ans]:=i;
                        dg(i+1);
                        dec(nodeans,node[i]);
                        nodejl[ans]:=0;
                        dec(ans);
                        bz[i]:=false;
                end;
        end;
end;
begin
        assign(input,'ratio.in');reset(input);
        assign(output,'ratio.out');rewrite(output);
        readln(n,m);
        for i:=1 to n do
        begin
                read(node[i]);
        end;
        for i:=1 to n do
        begin
                for j:=1 to n do
                begin
                        read(map[i,j]);
                        if map[i,j]<>0 then
                        begin
                                inc(dep);
                                route[dep].x:=i;
                                route[dep].y:=j;
                                route[dep].a:=map[i,j];
                        end;
                end;
        end;
        qs(1,dep);
        ratio:=maxlongint;
        fillchar(bz,sizeof(bz),false);
        for i:=1 to n do
        begin
                bz[i]:=true;
                inc(nodeans,node[i]);
                nodejl[1]:=i;
                ans:=1;
                dg(i+1);
                dec(nodeans,node[i]);
                bz[i]:=false;
        end;
        for i:=1 to m do write(sans[i],' ');
        writeln;
        close(input);close(Output);
end.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值