算法讨论:贪心+kruskal
1、首先删掉所有与根节点相连的边,这样整个图就变成了若干个极大联通子图,对每个极大联通子图进行一次最小生成树的计算,然后对于每个极大联通子图找一个离根节点最近的点。
2、根据这两步的结果求出每个点到达根节点所经道路中权值最大的边,如果这个点与根节点有边相连并且边权小于之前求出的最大边,那么更新答案并删边。
3、重复步骤2,直到没有可更新的点或者根节点度数达到限制。
POJ数据比较弱,不删边也能过。
代码:
program poj1639;//By_Thispoet
const
maxn=25;
maxm=10005;
var
i,j,k,m,n,p,q,tot,b,ans :longint;
l,r,d :array[0..maxm]of longint;
st,s :string;
namelist :array[0..maxn]of string;
father,color :array[0..maxn]of longint;
flag :array[0..maxn]of boolean;
fg :array[0..maxm]of boolean;
function root(i:longint):longint;
begin
if father[i]=i then exit(i);
father[i]:=root(father[i]);
exit(father[i]);
end;
function max(i,j:longint):longint;
begin
if i>j then exit(i);exit(j);
end;
procedure union(i,j:longint);
var x,y:longint;
begin
x:=root(i);y:=root(j);
father[x]:=y;
end;
procedure swap(var i,j:longint);
begin
if i<>j then
begin
i:=i xor j;j:=i xor j;i:=i xor j;
end;
end;
procedure qsort(ll,rr:longint);
var i,j,k:longint;
begin
i:=ll;j:=rr;k:=d[(i+j)>>1];
repeat
while d[i]<k do inc(i);
while d[j]>k do dec(j);
if i<=j then
begin
swap(d[i],d[j]);
swap(l[i],l[j]);
swap(r[i],r[j]);
inc(i);dec(j);
end;
until i>j;
if ll<j then qsort(ll,j);
if i<rr then qsort(i,rr);
end;
procedure dfs(i,fa:longint);
var j:longint;
begin
for j:=1 to n do
if (fg[j]) then
begin
if (l[j]=i)and(r[j]<>fa) then
begin
color[r[j]]:=max(color[i],d[j]);
dfs(r[j],i);
end;
if (r[j]=i)and(l[j]<>fa) then
begin
color[l[j]]:=max(color[i],d[j]);
dfs(l[j],i);
end;
end;
end;
procedure qsortc(l,r:longint);
var i,j,k:longint;
begin
i:=l;j:=r;k:=color[(i+j)>>1];
repeat
while color[i]>k do inc(i);
while color[j]<k do dec(j);
if i<=j then
begin
swap(color[i],color[j]);
inc(i);dec(j);
end;
until i>j;
if l<j then qsortc(l,j);
if i<r then qsortc(i,r);
end;
begin
readln(n);tot:=0;
for i:=1 to maxn do namelist[i]:='';
for i:=1 to n do
begin
readln(st);j:=1;
while st[j]<>' ' do inc(j);
s:=copy(st,1,j-1);
for p:=1 to tot+1 do
if namelist[p]=s then break;
if p=tot+1 then
begin
inc(tot);
namelist[tot]:=s;
end;
k:=j+1;
while st[k]<>' ' do inc(k);
s:=copy(st,j+1,k-j-1);
for q:=1 to tot+1 do
if namelist[q]=s then break;
if q=tot+1 then
begin
inc(tot);
namelist[tot]:=s;
end;
l[i]:=p;r[i]:=q;val(copy(st,k+1,length(st)-k),d[i]);
end;
qsort(1,n);
readln(m);
fillchar(fg,sizeof(fg),0);
for b:=1 to tot do
if namelist[b]='Park' then break;
for i:=1 to tot do father[i]:=i;
for i:=1 to n do
if (l[i]<>b)and(r[i]<>b) then
if root(l[i])<>root(r[i]) then
begin
inc(ans,d[i]);
union(l[i],r[i]);
fg[i]:=true;
end;
for i:=1 to n do
if ((l[i]=b)or(r[i]=b))and(root(l[i])<>root(r[i])) then
begin
inc(ans,d[i]);
fg[i]:=true;
union(l[i],r[i]);
dec(m);
end;
fillchar(color,sizeof(color),0);
dfs(b,0);
fillchar(flag,sizeof(flag),0);
for i:=1 to n do
if not fg[i] then
if l[i]=b then
begin
color[r[i]]:=color[r[i]]-d[i];
flag[r[i]]:=true;
end else if r[i]=b then
begin
color[l[i]]:=color[l[i]]-d[i];
flag[l[i]]:=true;
end;
p:=0;
for i:=1 to tot do
if flag[i] then
begin
inc(p);
color[p]:=color[i];
end;
qsortc(1,p);q:=0;
while (q<m)and(q<p) do
begin
if color[q+1]<0 then break else
dec(ans,color[q+1]);
inc(q);
end;
writeln('Total miles driven: ',ans);
end.