第一问dfs不说

第二问很容易让人想到最小树形图,但是我不会,而且时间复杂度也不允许

还有什么不同的方法呢?

首先想到的是prim的思想,设根节点已经确定,其他点未确定

我们就不断从已确定的点延伸,找到到未确定点中高度最高的那个点的最短边距(如果有多个高度相同的点,肯定选边距最短的)

将边距加入ans,并将这个点标为确定,重复上述,知道所有点都确定即可。

这样的算法没有问题,但是复杂度好像仍然不能AC

我们想,既然我们能用类似prim的思想,为什么不用Kruska呢?

Kruskal的问题在于,这个算法是不涉及到边的方向,用这个不能选出符合条件的解

考虑之前我们用类似prim的思想解题的时候,是以点的高度为第一关键字,然后再以距离为第二关键字

Kruskal对边排序的时候,我们是不是也可以考虑以点的高度为第一关键字,然后以距离为第二关键字排序呢?

就是这样,我们以边的终点高度为第一关键字降序,长度为第二关键字升序排序

然后按最小生成树的方法做就行了。

结果竟然TLE了,仔细对照一下别人的程序发现一直以来我的并查集写的是有问题的

我原来getfather是这么写的

function getf(x:longint):longint;

  begin

    while fa[x]<>x do x:=fa[x];

    exit(x);

  end;

而实际上多次调用这个函数,显然会进行很多冗余的运算

而正确的写法应该是

function getf(x:longint):longint;

  begin

    if fa[x]<>x then fa[x]:=getf(fa[x]); 

    exit(fa[x]);

  end;

这应该才是并查集所谓反阿克曼函数的时间复杂度吧

亡羊补牢,为时不晚;

  1 type node=record
  2        x,c,y,next:longint;
  3      end;
  4 
  5 var a:array[0..2000010] of node;
  6     fa,p,q,h:array[0..110010] of longint;
  7     v:array[0..110010] of boolean;
  8     len,x,y,z,n,m,i,j,k1,k2,t:longint;
  9     ans,e:int64;
 10 
 11 procedure swap(var a,b:node);
 12   var c:node;
 13   begin
 14     c:=a;
 15     a:=b;
 16     b:=c;
 17   end;
 18 
 19 function getf(x:longint):longint;
 20   begin
 21     if fa[x]<>x then fa[x]:=getf(fa[x]); // 22     exit(fa[x]);
 23   end;
 24 
 25 procedure add(x,y,z:longint);
 26   begin
 27     inc(len);
 28     a[len].y:=y;
 29     a[len].c:=z;
 30     a[len].x:=x;
 31     a[len].next:=p[x];
 32     p[x]:=len;
 33   end;
 34 
 35 procedure bfs;
 36   var i,f,x,y:longint;
 37   begin
 38     t:=1;
 39     q[1]:=1;
 40     v[1]:=true;
 41     f:=1;
 42     while f<=t do
 43     begin
 44       x:=q[f];
 45       i:=p[x];
 46       while i<>-1 do
 47       begin
 48         y:=a[i].y;
 49         if not v[y] then
 50         begin
 51           v[y]:=true;
 52           inc(t);
 53           q[t]:=y;
 54         end;
 55         i:=a[i].next;
 56       end;
 57       inc(f);
 58     end;
 59   end;
 60 
 61 procedure sort(l,r:longint);
 62   var i,j,x,y,z:longint;
 63   begin
 64     i:=l;
 65     j:=r;
 66     x:=a[(l+r) shr 1].c;
 67     y:=a[(l+r) shr 1].y;
 68     repeat
 69       while (h[a[i].y]>h[y]) or (h[a[i].y]=h[y]) and (a[i].c<x) do inc(i);
 70       while (h[y]>h[a[j].y]) or (h[a[j].y]=h[y]) and (x<a[j].c) do dec(j);
 71       if not(i>j) then
 72       begin
 73         swap(a[i],a[j]);
 74         inc(i);
 75         j:=j-1;
 76       end;
 77     until i>j;
 78     if l<j then sort(l,j);
 79     if i<r then sort(i,r);
 80   end;
 81 
 82 
 83 begin
 84   fillchar(p,sizeof(p),255);
 85   readln(n,m);
 86   len:=0;
 87   for i:=1 to n do
 88     read(h[i]);
 89   for i:=1 to m do
 90   begin
 91     readln(x,y,z);
 92     if h[x]>h[y] then add(x,y,z)
 93     else begin
 94       add(y,x,z);
 95       if h[x]=h[y] then add(x,y,z);
 96     end;
 97   end;
 98   bfs;
 99   sort(1,len);
100   for i:=1 to n do
101     fa[i]:=i;
102   i:=0;
103   j:=0;
104   for j:=1 to len do
105   begin
106     if not(v[a[j].x] and v[a[j].y]) then continue;  //首先必须是能访问到的点
107     k1:=getf(a[j].x);
108     k2:=getf(a[j].y);
109     if k1<>k2 then
110     begin
111       fa[k2]:=k1;
112       e:=a[j].c;
113       ans:=ans+e;
114       inc(i);
115     end;
116   end;
117   writeln(t,' ',ans);
118 end.
View Code

 

posted on 2014-07-19 13:15  acphile  阅读(197)  评论(0编辑  收藏  举报