算法讨论:贪心+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.