POJ1639 Picnic Planning —— 根节点度数有限制的最小生成树

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

你可能感兴趣的:(最小生成树)