2016.08.17【初中部 NOIP提高组 】模拟赛C题解
来源:互联网 发布:java异常中的finally 编辑:程序博客网 时间:2024/05/20 22:41
T1:
第一道题本以为很水,然后,我差点就挂了(注意还没挂)。只是,程序是压着950MS的线过的!数据太水没办法233333.
我来介绍我的方法,和我的同学神犇们一种10MS水过的方法。
解1:
很明显,非正解的暴力方法,就是枚举位置(i,j),然后在用双重循环,枚举最近的。
做出来我们发现。这样182^4一定是会超时的。让我们分析一下:一开始的二重循环是必须的,是必须枚举每个位置的,于是我们就想办法把后面的二重循环去掉,改成一个更加优化的方法。
考试的时候,我脑子里冒出了2个想法,队列和前缀和。前缀和撇开,剩下一个一找到就是最优解的队列。所以,我们用队列实现第一题,从为“1”的点到每个点的位置扩四周散开来,就可以AC了,不过不优。
procedure doit;begin fillchar(dis,sizeof(dis),7);//dis代表当前位置到"1"的最短路 for i:=1 to n do for j:=1 to m do if a[i,j]='1' then bfs(i,j);end;解2:
可以直接把1个位置丢进队列,然后再按照bfs做一次就可以了,这样不用bfs多个,同时bfs就可以了。
借鉴一位神犇的代码:
for i:=1 to n do begin for j:=1 to m do begin read(ch[i,j]); if ch[i,j]='1' then begin inc(tail); d[tail,1]:=i; d[tail,2]:=j;//丢进队列 bz[i,j]:=false; f[i,j]:=0;//f跟dis一样 end; end; readln; end;当然,解法1这么做,如果有BT数据几乎全都是1的话是过不了的。所以,我们加个优化,没碰到1才把当前元素丢进队列。
紧急报道:
第一题还可以用DP来做:
设f[i,j]表示这个位置离"1"的最近位置。我们对于开始并不是1个位置赋值为一个∞,是1的赋值为0,对于四周进行DP。
for k:=1 to n+m do for i:=1 to n do for j:=1 to m do a[i,j]:=mini(a[i-1][j]+1,a[i,j-1]+1,a[i+1,j]+1,a[i,j+1]+1,a[i,j]);对于K,因为最多更新n+m次,至于为什么,我还是请教了一位匿名为波波的大神,原因是最多更新第一行,一行为m,第一列,一列为n次,所以为m+n
T2:
第二道题很容易想到SPFA,以外星人霸占了的城市进行SPFA,最后模拟判断就可以了。不过如此也是压线过的。这里有个优化,如果当前每个城市都不适合居住,那么以后都是不适合居住的了,请选手们自行更改。虽然说数据水过了,但是,用邻接表存这个数据的时候,如果有BT数据数组还是会爆。所以可以使用另外的数据结构存。A了就不改了23333.
for j:=1 to k do begin readln(x); head:=0; tail:=1; d[1]:=x; fillchar(min,sizeof(min),7); min[x]:=0; while head<>tail do begin inc(head); now:=d[head]; for i:=1 to b[now,0] do if (min[b[now,i]]>min[now]+a[now,i]) then begin min[b[now,i]]:=min[now]+a[now,i]; inc(tail); d[tail]:=b[now,i]; end; end; ans:=0; for i:=1 to n do if (min[i]>=k1)and(not bz[i]) then inc(ans) else bz[i]:=true; writeln(ans); end;T3:
第三题膜拜了大神一次又一次还是不肯教我。幸亏一堆人高呼”克鲁斯卡尔大法“,所以水水的想出了正解,蒟蒻地打错了变量。要是我考试的时候能调试一下就好了。
对于每2点间的数进行排序
for i:=1 to n-1 do for j:=i+1 to n do begin inc(k); b[k]:=sqrt(sqr(a[i,2]-a[j,2])+sqr(a[i,1]-a[j,1]));//精确的两点距离方法。 c[k,1]:=i; c[k,2]:=j; end;
按照克鲁斯卡尔做一次,如果连接了m-n条边,就把已经连通的取一个最大值,输出即可。
<span style="font-size:18px;">q(1,k); for i:=1 to k do begin if getfather(c[i,1])<>getfather(c[i,2]) then//没联通就连通 begin he(c[i,1],c[i,2]); inc(sum);//联通了多少边 if b[i]>max then max:=b[i]; end; if sum=n-m then begin writeln(max:0:2); halt; end; end;</span>T4:
60%并查集
80%暴力枚举用dfs判断就可以了。
100%其实一般做出80分都应该可以想到100分的算法,我们发现,80分的算法慢的原因的进行了多次dfs,但是细心的人可以发现有很多是不必要的,已经做过的。
用f[x]表示以x为根节点,往下找他的儿子有多少个(包括自己),于是开始用递归预处理一下f数组(我递归没学好打了1个小时)
function dfs(x:longint):longint;var i:longint;begin bz[x]:=true;//到达过 for i:=1 to b[x,0] do//以x为根节点他的儿子个数 begin if not bz[b[x,i]] then//如果当前点没到达过 f[x]:=f[x]+dfs(b[x,i]);//递归,b[x,i]为以x根节点第i个儿子。 end; f[x]:=f[x]+1;//加上自己 exit(f[x]);//路径压缩end;然后一切就容易了。用样例来说,他的图是:
是这个样子的,可是这样不算是一棵标准的树,所以很难看出怎么递归。我改一下变成这样:
美术差生请别注意。绿色则是f数组,这就是样例的树。
假如我们去掉3这个位置,看他有多少个子节点,4他对应的儿子有2,8对应的儿子有5,如果就是这样结束就容易了。可是TM他还有爸爸,所以,我们就用总数减去当前需要删掉的3他的儿子,10-8=2.然后答案就是2,2,5,每个都符合条件就输出。
当然,怎么判断是不是父亲节点是个问题。
父亲节点的儿子数一定比自己这个儿子大,用这个判断就好。
for i:=1 to n do begin bb:=true; for j:=1 to b[i,0] do//枚举儿子以及父亲,预处理处理过 if f[b[i,j]]>f[i] then//如果当前点是父亲节点 begin if f[1]-f[i]>n div 2 then//看看是否符合条件 begin bb:=false; break; end; end else begin if f[b[i,j]]>n div 2 then//儿子节点就直接判断符合性 begin bb:=false; break; end; end; if bb then begin writeln(i); kk:=true; end; end; if not kk then writeln('NONE');总结:
图论是我的弱项,看到这个我就怕了。其实没什么好怕的,多思考,多写肯定能想出来。
当然这次比赛马虎的地方也很多,导致丢了200分。
如果有题目不会打代码也要硬着头皮码下代码,说不定能骗出一点分。
下次继续努力,好吧没下次,明天开始刷普及,不过持续更新C组的题解和题目,欢迎大神指导。
- 2016.08.17【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.17【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.17【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.11【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.11【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.12【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.12【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.13【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.13【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.13【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.12【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.14【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.14【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.11【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.15【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.14【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.15【初中部 NOIP提高组 】模拟赛C题解
- 2016.08.15【初中部 NOIP提高组 】模拟赛C题解
- poj 3087 Shuffle'm Up
- 【zzulioj 1915 三维数组】
- Merge Intervals解题报告
- BZOJ3526 [Poi2014]Card
- 一次快排
- 2016.08.17【初中部 NOIP提高组 】模拟赛C题解
- #ifndef #define #endif的用法
- n a^o7 !
- 客户端多线程向服务端的文件传输
- java对象与json对象间的相互转换
- angularjs的使用:过滤器(5)
- UVA1386 快速矩阵幂 O(n²logk)
- C++模拟键盘按键
- zzulioj 1918 【二分最大匹配】