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