一道黑人的题

来源:互联网 发布:ios 淘宝首页布局 编辑:程序博客网 时间:2024/04/17 06:43

  前段时间校内测,出了一套水题,黑了俩学长,也学到了很多

  其中一道题大致题意是这样的:在一个N*N的带权网格图中,找一条从左上角到右下角的路径(可以重复走),使路径上权值的最大值和最小值的差最小,求这个最小值,其中N≤100,点权≤3000

  这是很久之前做的一道题的加强版,原题N≤100,点权≤110,最初做这题时,还是个没参加过NOIP的渣渣,连枚举答案+验证连通都想不到,那时候标算是二分答案+验证连通,是枚举最低点,二分最高点,再进行验证连通,复杂度是O(WlogW*N^2),W是点权,当时懵懵地懂了,第二次再碰到这题时,我写的也是二分答案+验证连通,只不过是先二分答案,再枚举最低点进行验证,当时体会了一下,觉得这样会优化下来很多,省去很多没有必要的步骤,大概知道啥意思,但是讲不清楚,和老师争论了一番,最后不了了之,这次出这道题原意是想按这个复杂度,点权可以扩大到1000,数据扩大后两个方法的差异会明显,然后测完之后发现自己这个跑得飞快,原本那个标算TLE~~,然后很兴奋的找神犇验题,神犇很不好意思地说:“我只会W*N^2的方法”然后就是妥妥地石化,后来和学长讨论了一下题目,又领会了一下,发现其实不需要二分枚举,因为两个端点的移动本来就是单调的,所以很显然对于端点的枚举可以O(N)进行实现,所以就是W*N^2了,为了卡常(有些无良),我把点权升到3000,1s时限,不开O2,然后考试时就出现了很有趣的一件事:学长们一直揪心卡常问题在优化,还有一个神犇学长自己内部开O2然后出了个神奇bug就100→0了,妥妥直播尴尬

不多说,贴代码

 const flag:array[0..3,0..1]of longint=((-1,0),(0,1),(1,0),(0,-1)); var n,ans:longint;     vis:array[0..105,0..105]of boolean;     a:array[0..105,0..105]of longint; procedure init;  var i,j:longint;   begin    assign(input,'mismatching.in');reset(input);    assign(output,'mismatching.out');rewrite(output);    readln(n);ans:=0;    for i:=1 to n do     begin      for j:=1 to n do        begin        read(a[i,j]);        if a[i,j]>ans then ans:=a[i,j];       end;      readln;     end;   end; function check(x,y:longint):boolean;  begin   if (x<1)or(y<1)or(x>n)or(y>n) then exit(false);   if vis[x,y] then exit(false);   exit(true);  end; procedure dfs(minh,maxh,x,y:longint);  var i,xx,yy:longint;   begin    vis[x,y]:=true;    for i:=0 to 3 do     if check(x+flag[i,0],y+flag[i,1]) then      begin       xx:=x+flag[i,0];       yy:=y+flag[i,1];       if (a[xx,yy]>=minh)and(a[xx,yy]<=maxh) then dfs(minh,maxh,xx,yy);      end;   end; procedure main;  var i,j,L,R,bo,h0,h1,mid:longint;   begin    L:=ans;R:=ans;    while (L>=0)and(L<=R) do     begin      bo:=0;      if (a[1,1]>=L)and(a[1,1]<=R) then begin                                         fillchar(vis,sizeof(vis),0);                                         dfs(L,R,1,1);                                         if vis[n,n] then begin                                                           if R-L<ans then ans:=R-L;                                                           bo:=1;                                                          end;                                        end;      if bo=0 then dec(L)              else dec(R);      while not(L<=R) do dec(L);     end;   end; procedure print;  begin   writeln(ans);   close(input);close(output);  end; begin  init;  main;  print; end.
写得比较LOW,不喜勿喷

2016/11/2 23:37:10

【写的有漏洞的,欢迎路过大神吐槽】
Ending.

1 0