Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
雁过留声——小记在Linux下写程序听说NOIP要用NOILinux,我马不停蹄的开始了适应。 之所以用这题来练手,主要因为它比较简单...但是,想AC不容易。 安装NOILinux不是一个容易事,我采取了一个妥协的方法: 使用VMWare虚拟机。但是发现一个可怕的事情:虚拟机中文件无法 复制到物理机上。怎么办呢? 再次妥协:让虚拟机使用软盘,再用WinImage读取。 上次比赛时听说几个IDE均出现了问题,我就用gedit+g+++gdb来写程序 gedit 3246.cpp 编辑 g++ 3246.cpp -o 3246 -Wall 编译,-Wall生成所有警告,挺实用的 ./3246 运行 g++ 3246.cpp -o 3246 -Wall -g -g生成调试信息 gdb 3246 调试 首先说说这题算法: 用GrahamScan扫描求出一个凸包,然后对每个凸包上的点: 去除它, 设凸包上它的前驱与后继为x,y, 把极角排序后位于x与y之间的点求个凸包, 计算面积。 问题一般出在移除最左下的那个“基准”点上,我的策略: 删了它,重新求凸包。 计算几何貌似是从来不卡常数的(也许有例外),于是我就写的比较工程, 判断方向、面积、排序都单独用比较一般的函数实现 int Direction(int i,int j,int k){ long long t=(X[j]-X[i])*(Y[k]-Y[i])-(X[k]-X[i])*(Y[j]-Y[i]); if (t>0)return 1; if (t==0)return 0; return -1; } long long Dist(int a,int b){ return (X[a]-X[b])*(X[a]-X[b])+(Y[a]-Y[b])*(Y[a]-Y[b]); } long long area(int a,int b){ long long s=((X[a]-X[0])*(Y[b]-Y[0])-(X[b]-X[0])*(Y[a]-Y[0])); if (s<0)s=-s; return s; } void exchange(int a,int b){ long long t; t=X[a];X[a]=X[b];X[b]=t; t=Y[a];Y[a]=Y[b];Y[b]=t; } void qs(int b,int e){ if (b>=e)return; exchange(b,(b+e)>>1); int j; for (int i=j=b+1;i<=e;i++)if (Direction(0,i,b)==1 || Direction(0,i,b)==0 && Dist(0,i)<Dist(0,b)) exchange(i,j++); exchange(--j,b); qs(b,j-1);qs(j+1,e); } 剩下的扫描、主程序都比较简单了。 强烈提示wa的人:正确处理共线是一个AC的凸包的一半。 long long Scan(int b,int e,int *buf,int &m,int delta=-1){ //delta这个点在扫描的时候将被忽略,相当于被删除 m=1;buf[0]=0; for (int i=b;i<=e;i++)if (i!=delta){ buf[m++]=i; while (m>3 && Direction(buf[m-2],buf[m-1],buf[m-3])==-1) buf[m-2]=buf[m-1],m--; } long long r; r=0; for (int i=1;i<m-1;i++)r+=area(buf[i],buf[i+1]); return r; } 看一眼数据规模,是要用long long的。 这时候,一个很纠结的问题出现了: 如何输出long long?用哪种方式? printf("%lld",a)//for Linux printf("%I64d",a)//for POJ cout<<a//...it's too slow 这个问题让我思考了很久,最终决定:自己写一个输出函数 void printll_(long long a){ if (a!=0){ printll_(a/(long long)10); printf("%d",int(a%(long long)10)); } } void printll(long long a){ if (a==0)printf("0"); else if (a>0)printll_(a); else if (a<0){ putchar('-'); printll(-a); } } 写好了,交上去,挂了。 怎么办? 随便编几个数据: 4 0 0 0 1 1 0 1 1 16 0 0 0 1 0 2 0 3 1 0 1 1 1 2 1 3 2 0 2 1 2 2 2 3 3 0 3 1 3 2 3 3 4 0 0 100 0 1 0 1 1 4 0 0 100 0 0 1 1 1 4 0 0 0 100 1 0 1 1 4 0 0 1 0 0 1 100 100 结果,跑第三个数据的时候,输出49.50 赶紧调试,一想到有一个叫gdb的好东西,就不用自己的土鳖调试法了。 (gdb)break 84 (gdb)print a2 ...... 一直追踪到最后输出结果部分都是正确的。 在一看代码: printll(a2/(long long)2); 怪不得,打错变量了。 printll(ret/(long long)2); 改,运行。 然而,最后一组数据挂了。 接着追踪,愕然发现:调用Scan忘记设置delta了。 接着修改,通过软盘拷贝出,提交...终于AC啦! 说一下用Linux我的几个习惯: 它有一个切换桌面的功能,于是,我就把系统管理、编程的窗口分到两个桌面上, 免去了很多麻烦! 编译、运行、调试都要用不同的命令,都挺长的......我就 各开一个终端,再次操作的时候按↑键再回车就可以了。 gdb真是个好东西!使用它可以让工作量大大降低。 不过,它在windows下的各个IDE中表现貌似很惨。 Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator