滑雪场评级{Gold题3}
【问题描述】
滑雪场用一个M*N(1 <= M,N <= 500)的数字矩阵表示海拔高度,每个数字表示一个范围在0 .. 1,000,000,000的高度。有些格子被指定为起点,组织者想对这些起点做难度评级。
如果起点P点是一个难度级别为D的起点,则D必须是满足以下条件的一个最小值:
(1)从一个格子只能滑到相邻的格子;
(2)这两个格子的海拔差不超过D;
(3)至少能够到达T(1 <= T <= M*N)个格子(包括起点本身)。
【文件输入】
第一行,三个用空格隔开的整数,分别表示M,N和T。
接下来2.. M+1行,每行一个N个整数,表示海拔。
接下来M+2.. 2M+1行,每行一个整数0或者1,其中1表示该格子是一个起点。
【文件输出】
共一行,一个整数,所有起点的难度和。
【输入样例】
3 5 10
20 21 18 99 5
19 22 20 16 17
18 17 40 60 80
1 0 0 0 0
0 0 0 0 0
0 0 0 0 1
【输出样例】
24
【样例说明】
左上角的格子是一起点,难度为4,右下角的格子是一个起点,难度为20。
思路:这道题原来以为只要二分再搜索就可以AC了,结果发现差的还是有点远了,只过了一个点。后来请教某大牛得知原来这题的算法主要是用最小生成树的kruskal算法,把整个图用边连接起来,边的权值等于两个点之间的高度差绝对值,然后对边进行快排,每次加入最小的一条边,当边数大于题目要求的t时,深搜整个图,此时搜到的起点的难度值即为当前加进去边的权值。下面上代码
1 type node=record 2 s,t,w:longint; 3 end; 4 5 var 6 v:array[0..500000]of node; //v表示每条边的端点以及权值 7 fa,size:array[0..250000]of longint; //fa表示每个点的父节点;size表示每个连通块所包含的点的数量 8 h:array[0..500,0..500]of longint; 9 used,isstart:array[0..250000]of boolean; //used表示每个点是否已经搜索过;isstart表示该点是否为起点 10 map:array[0..250000,0..4]of longint; //map表示每个点所连通的点 11 n,m,kk,ss,ans:int64; //ss表示边的条数 12 13 procedure openit; 14 begin 15 assign(input,'skilevel.in');assign(output,'skilevel.out'); 16 reset(input);rewrite(output); 17 end; 18 19 procedure closeit; 20 begin 21 close(input);close(output); 22 end; 23 24 procedure qsort(l,r:longint); 25 var i,j,m:longint; 26 t:node; 27 begin 28 i:=l;j:=r;m:=v[(l+r) div 2].w; 29 repeat 30 while v[i].w<m do inc(i); 31 while v[j].w>m do dec(j); 32 if not (i>j) then 33 begin 34 t:=v[i];v[i]:=v[j];v[j]:=t; 35 inc(i);dec(j); 36 end; 37 until i>j; 38 if l<j then qsort(l,j); 39 if i<r then qsort(i,r); 40 end; 41 42 function getfather(x:longint):longint; 43 begin 44 if fa[x]=x then exit(x); 45 fa[x]:=getfather(fa[x]); 46 getfather:=fa[x]; 47 end; 48 49 procedure datain; 50 var i,j,num:longint; 51 begin 52 readln(n,m,kk); 53 for i:=1 to n do 54 begin 55 for j:=1 to m do read(h[i,j]); 56 readln; 57 end; 58 for i:=1 to n do 59 begin 60 for j:=1 to m do 61 begin 62 read(num); 63 if num=1 then isstart[(i-1)*m+j]:=true; 64 end; 65 readln; 66 end; 67 for i:=1 to n do 68 for j:=1 to m do 69 begin 70 if i<n then 71 begin 72 inc(ss); 73 v[ss].s:=(i-1)*m+j; 74 v[ss].t:=i*m+j; 75 v[ss].w:=abs(h[i,j]-h[i+1,j]); 76 end; 77 if j<m then 78 begin 79 inc(ss); 80 v[ss].s:=(i-1)*m+j; 81 v[ss].t:=(i-1)*m+j+1; 82 v[ss].w:=abs(h[i,j]-h[i,j+1]); 83 end; 84 end; 85 for i:=1 to n*m do //初始化 86 begin 87 fa[i]:=i; 88 size[i]:=1; 89 end; 90 qsort(1,ss); //快排权值 91 end; 92 93 procedure dfs(pos,cur:longint); 94 var i:longint; 95 begin 96 used[pos]:=true; 97 if isstart[pos] then 98 begin 99 ans:=ans+cur; 100 isstart[pos]:=false; 101 end; 102 for i:=1 to map[pos,0] do 103 if not used[map[pos,i]] then dfs(map[pos,i],cur); 104 end; 105 106 procedure kruskal; //运用最小生成树的思想进行求解 107 var i,j,x,y:longint; 108 begin 109 for i:=1 to ss do 110 begin 111 x:=getfather(v[i].s); 112 y:=getfather(v[i].t); 113 if x<>y then 114 begin 115 if (size[x]<kk) and (size[x]+size[y]>=kk) then dfs(x,v[i].w); 116 if (size[y]<kk) and (size[x]+size[y]>=kk) then dfs(y,v[i].w); 117 fa[y]:=x; 118 size[x]:=size[x]+size[y]; 119 inc(map[v[i].s,0]); 120 map[v[i].s,map[v[i].s,0]]:=v[i].t; 121 inc(map[v[i].t,0]); 122 map[v[i].t,map[v[i].t,0]]:=v[i].s; 123 end; 124 end; 125 end; 126 127 128 begin 129 openit; 130 datain; 131 kruskal; 132 writeln(ans); 133 closeit; 134 end.