您的位置:首页 > 其它

日常训练20161018 证据

2016-10-18 16:14 211 查看
有一幅n个点,m条边的无向图,取一些边使得图是一个由k棵树构成的森林并且分数最大。分数定义为边权积,但图中有若干坏点,坏点所在联通块的边权不计入内。求最大分数。若无方案输出-1。

贪心的思想,一开始先连好点之间的边,再连坏点之间的边,若还需要继续连边,则必须连好点与坏点之间的边,会损失一些权值,每次挑最小损失的联通块连到坏点即可。(比损失的时候对乘积取log就能比较大小了)

type
rec=record
v:extended;
i:longint;
end;
const
p=1000000007;
var
heap:array[0..200050] of rec;
fact,x,y,z,fa,flag,chs:array[0..200050] of longint;
tot:array[0..200050] of extended;
n,m,k,i,cnt:longint;
ans:int64;
t:rec;
procedure swap(var a,b:longint);
var t:longint;
begin t:=a;a:=b;b:=t;end;
procedure sort(l,r:longint);
var
i,j,e:longint;
begin
i:=l;j:=r;e:=z[(l+r)>>1];
repeat
while z[i]>e do inc(i);
while e>z[j] do dec(j);
if not (i>j) then
begin
swap(x[i],x[j]);
swap(y[i],y[j]);
swap(z[i],z[j]);
inc(i);dec(j);
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
function find(x:longint):longint;
begin
if fa[x]=x then exit(x);
fa[x]:=find(fa[x]);
exit(fa[x]);
end;
procedure choose_useful;
var
i,f1,f2:longint;
begin
for i:=1 to m do
begin
if (fact[x[i]]=0) or (fact[y[i]]=0) then continue;
f1:=find(x[i]);
f2:=find(y[i]);
if (k>0)and(f1<>f2) then
begin
dec(k);
fa[f1]:=f2;
tot[f2]:=tot[f1]+tot[f2]+ln(z[i]);
chs[i]:=1;
if (k=0) then exit;
end;
end;
end;
procedure choose_useless;
var
i,f1,f2:longint;
begin
for i:=1 to m do
begin
if (fact[x[i]]=1) or (fact[y[i]]=1) then continue;
f1:=find(x[i]);
f2:=find(y[i]);
if (k>0)and(f1<>f2) then
begin
dec(k);
fa[f1]:=f2;
if (k=0) then exit;
end;
end;
end;
procedure heap_up(x:longint);
var
t:rec;
begin
while (x>1)and(heap[x].v<heap[x>>1].v) do
begin
t:=heap[x];heap[x]:=heap[x>>1];heap[x>>1]:=t;
x:=x>>1;
end;
end;
procedure heap_down(x:longint);
var
t:rec;
e:longint;
begin
while (x<<1<=cnt)and(heap[x].v>heap[x<<1].v)or(x<<1+1<=cnt)and(heap[x].v>heap[x<<1+1].v) do
begin
if (x<<1+1<=cnt)and(heap[x<<1+1].v<heap[x<<1].v)
then e:=x<<1+1
else e:=x<<1;
t:=heap[x];heap[x]:=heap[e];heap[e]:=t;
x:=e;
end;
end;
procedure push(t:rec);
begin
inc(cnt);
heap[cnt]:=t;
heap_up(cnt);
end;
function poop:rec;
begin
poop:=heap[1];
heap[1]:=heap[cnt];
dec(cnt);
heap_down(1);
end;
procedure print(x:longint);
begin
writeln(x);
close(input);close(output);
halt;
end;
begin
assign(input,'evidence.in');reset(input);
assign(output,'evidence.out');rewrite(output);
read(n,m,k);k:=n-k;
for i:=1 to n do read(fact[i]);
for i:=1 to m do read(x[i],y[i],z[i]);
for i:=1 to n do fa[i]:=i;
sort(1,m);
if (k>0) then choose_useful;
if (k>0) then choose_useless;
for i:=1 to m do
if (fact[x[i]]<>fact[y[i]]) then
begin
if (fact[y[i]]=1) then swap(x[i],y[i]);
flag[find(x[i])]:=1;
end;
for i:=1 to n do
if (flag[i]=1) then
begin
t.v:=tot[i];
t.i:=i;
push(t);
end;
while (cnt>0)and(k>0) do
begin
t:=poop;
flag[t.i]:=2;
dec(k);
end;
if (k>0) then print(-1);
ans:=1;
for i:=1 to m do
if (chs[i]=1)and(flag[find(x[i])]<2)
then ans:=ans * z[i] mod p;
print(ans);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  贪心