【重口味。。】CTSC2011杀菌计划

在奋战了7个小时后才AC了这道题的人只能瞻仰在考场上AC的FHQ了。。。

代码很恐怖,写了350行8KB,最可恶的是一页草稿纸的伪代码和各种特殊情况。

 

涉及的几个关键字:三维叉积、半平面交、梯形剖分

 

三维叉积的一个核心操作就是:三维旋系,另外还需要用来写:面面交,面线交,判三维空间上下左右,二维投影。

 

具体做法是:

      一束光线首先在每一个面上投一个影,然后这个投影需要和这个面求一个交集(这里我用的是半平面交),之后再反射递归。

 

      计算答案时将每个面上曾经经过的所有投影求一个面积并(梯形剖分)。

 

当然细节很多,不过还好栋哥没有出细节太多的数据,本来我4.30小时过了样例之后直接去测就已经过了7个点,但令我哭笑不得的是第6个点(全部面积之和)和第7个点(0)错了。。。之后又发现疏漏了几种特殊情况。。

 

很郁闷的是半平面交又错了老地方:最开始的时候忘记判平行和判无解

 

扣的:

program ctscbox; uses math; const e=1e-7; type point=record x,y,z:real end; jid=record x,y,z:point end; side=record n:longint; o:array[0..20] of point; d:jid; end; fs=record g:point; p:side; end; cm=object n:longint; m:array[0..20] of side; function cal:real; procedure new(a:side); end; var dd:array[0..100] of point; q:array[0..100] of cm; a:array[0..100] of side; m,n,i,j,k,lim:longint; ans:real; f:fs; operator -(a,b:point)c:point;begin c.x:=a.x-b.x;c.y:=a.y-b.y;c.z:=a.z-b.z end; operator +(a,b:point)c:point;begin c.x:=a.x+b.x;c.y:=a.y+b.y;c.z:=a.z+b.z end; operator /(a,b:point)c:real;begin c:=a.x*b.x+a.y*b.y+a.z*b.z end; function len(a:point):real;begin with a do len:=sqrt(x*x+y*y+z*z) end; operator /(a:point;b:real)c:point;begin c.x:=a.x/b;c.y:=a.y/b;c.z:=a.z/b end; operator *(a:point;b:real)c:point;begin c.x:=a.x*b;c.y:=a.y*b;c.z:=a.z*b end; procedure cm.new(a:side);begin inc(n);m[n]:=a end; operator *(a,b:point)c:point; begin c.x:=a.y*b.z-a.z*b.y; c.y:=a.z*b.x-a.x*b.z; c.z:=a.x*b.y-a.y*b.x; end; function ro(a:jid;b:point):point; begin ro.x:=a.x/b; ro.y:=a.y/b; ro.z:=a.z/b; end; function ro(a:jid;b:side):side;var i:longint; begin ro:=b; with ro do begin for i:=1 to n do o[i]:=ro(a,o[i]); end; end; function ro(a,b:jid):jid; begin ro.x:=ro(a,b.x); ro.y:=ro(a,b.y); ro.z:=ro(a,b.z); end; procedure ro(var a:side); var i:longint; p:point; begin with a do begin p:=o[n]*o[1]; for i:=1 to n-1 do p:=p+(o[i]*o[i+1]); if p.z<0 then for i:=1 to n>>1 do begin p:=o[i];o[i]:=o[n+1-i]; o[n+1-i]:=p; end; end; end; function cm.cal:real; var a,b,x1,x2,z:array[0..100] of real; s,o:array[0..100] of longint; c:array[0..1000] of real; dx,mx,pre:real; i,j,tn,nn,nj,now:longint; function inq(a:real;i:longint):boolean; begin inq:=(x1[i]<a+e) and (a<x2[i]+e) or (x2[i]<a+e) and (a<x1[i]+e); end; procedure new3(sx,sy,tx,ty:real);var i:longint; begin inc(nj);c[nj]:=sx; if abs(sx-tx)<e then exit; inc(nn); x1[nn]:=sx;x2[nn]:=tx; a[nn]:=(ty-sy)/(tx-sx); b[nn]:=sy-a[nn]*sx; o[nn]:=1-2*ord(sx>tx); for i:=1 to nn-1 do if abs(a[i]-a[nn])>e then begin sx:=(b[i]-b[nn])/(a[nn]-a[i]); if inq(sx,i) and inq(sx,nn) then begin inc(nj);c[nj]:=sx; end; end; end; procedure new2(var m:side);var i:longint; begin with m do begin for i:=1 to n-1 do new3(o[i].x,o[i].y,o[i+1].x,o[i+1].y); new3(o[n].x,o[n].y,o[1].x,o[1].y); end; end; procedure sort1(l,r:longint);var i,j:longint;x,y:real; begin if l>=r then exit; i:=l;j:=r;x:=c[(l+r)>>1]; repeat while c[i]<x-e do inc(i); while c[j]>x+e do dec(j); if i<=j then begin y:=c[i];c[i]:=c[j];c[j]:=y; inc(i);dec(j); end; until i>j; sort1(l,j);sort1(i,r); end; procedure sort2(l,r:longint);var i,j,t:longint;x,y:real; begin if l>=r then exit; i:=l;j:=r;x:=z[(l+r)>>1]; repeat while z[i]<x-e do inc(i); while z[j]>x+e do dec(j); if i<=j then begin y:=z[i];z[i]:=z[j];z[j]:=y; t:=s[i];s[i]:=s[j];s[j]:=t; inc(i);dec(j); end; until i>j; sort2(l,j);sort2(i,r); end; begin nn:=0;nj:=0;cal:=0; for i:=1 to n do ro(m[i]); for i:=1 to n do new2(m[i]); sort1(1,nj); for i:=2 to nj do if abs(c[i]-c[i-1])>e then begin dx:=c[i]-c[i-1]; mx:=(c[i]+c[i-1])/2; tn:=0; for j:=1 to nn do if inq(mx,j) then begin inc(tn); z[tn]:=mx*a[j]+b[j]; s[tn]:=o[j]; end; sort2(1,tn); now:=0; for j:=1 to tn do begin if now=0 then pre:=z[j]; now:=now+s[j]; if now=0 then cal:=cal+(z[j]-pre)*dx; end; end; end; function jiao(m1,m2:side):side; var q,p:array[0..100] of longint; a,b,c,v,x,y,ji:array[0..100] of real; i,j,t,l,r,nn:longint; ok:boolean; procedure new(var m:side); var i:longint; p:point; begin with m do begin for i:=1 to n do begin inc(nn); if i=n then p:=o[1]-o[n] else p:=o[i+1]-o[i]; a[nn]:=-p.y;b[nn]:=p.x; c[nn]:=a[nn]*o[i].x+b[nn]*o[i].y; v[nn]:=c[nn]/sqrt(a[nn]*a[nn]+b[nn]*b[nn]); ji[nn]:=arctan2(b[nn],a[nn]); end; end; end; procedure jd(t,j:longint;var x,y:real);var s:real; begin x:=c[t]*b[j]-c[j]*b[t]; y:=c[t]*a[j]-c[j]*a[t]; s:=a[t]*b[j]-a[j]*b[t]; if abs(s)<e then begin ok:=true;exit; end; x:=x/s;y:=-y/s; end; begin nn:=0; ok:=false; ro(m1);ro(m2); new(m1);new(m2); for i:=1 to nn do p[i]:=i; for i:=1 to nn do for j:=i+1 to nn do if ji[p[i]]>ji[p[j]]+e then begin t:=p[i];p[i]:=p[j];p[j]:=t; end; l:=1;r:=0; for i:=1 to nn do begin j:=p[i];t:=q[r]; if (l<=r)and(abs(ji[j]-ji[t])<e) then if v[j]>v[t] then dec(r) else continue; while (l<r)and(x[r]*a[j]+y[r]*b[j]<c[j]+e) do dec(r); while (l<r)and(x[l+1]*a[j]+y[l+1]*b[j]<c[j]+e) do inc(l); t:=q[r];inc(r);q[r]:=j; if l<r then jd(t,j,x[r],y[r]); end; while (l<r)and(x[r]*a[q[l]]+y[r]*b[q[l]]<c[q[l]]+e) do dec(r); jd(q[l],q[r],x[l],y[l]); with jiao do begin n:=r-l+1; for i:=1 to n do begin o[i].x:=x[l+i-1]; o[i].y:=y[l+i-1]; o[i].z:=0; end; end; if ok then jiao.n:=0; end; procedure inc(var a:side;b:real);var i:longint; begin with a do begin for i:=1 to n do o[i].z:=o[i].z+b end; end; procedure work(f:fs;lim:longint); var dt:array[0..100] of real; i,j,pn:longint; mx,dz:real; k:fs; pj:jid; mm,na:side; procedure ck(i,j:longint);var t:longint; begin if dt[i]>dt[j] then begin t:=i;i:=j;j:=t; end; if (dt[i]>e)or(dt[j]<e) then exit; with mm do o[i]:=o[j]+(o[i]-o[j])*(dt[j]/(dt[j]-dt[i])); dt[i]:=0; end; begin if lim=0 then exit; for i:=1 to n do begin with pj.x do begin x:=1;y:=0;z:=0 end; with pj.y do begin x:=0;y:=1;z:=0 end; with pj.z do begin x:=0;y:=0;z:=1 end; pj:=ro(a[i].d,pj); k.g:=ro(a[i].d,f.g); k.p:=ro(a[i].d,f.p); na:=ro(a[i].d,a[i]); dz:=na.o[1].z; inc(k.p,-dz); inc(na,-dz); if abs(k.g.z)<e then continue; mm:=k.p;mx:=0;pn:=0; with mm do begin for j:=1 to n do begin dt[j]:=-o[j].z/k.g.z; if dt[j]>mx then mx:=dt[j]; if dt[j]<-e then pn:=j; end; if pn>0 then begin for j:=n downto pn do o[j+1]:=o[j]; for j:=n downto pn do dt[j+1]:=dt[j]; n:=n+1; end; end; if mx<e then continue; for j:=1 to mm.n-1 do ck(j,j+1); ck(mm.n,1); with mm do begin pn:=n;n:=0; for j:=1 to pn do if dt[j]>-e then begin n:=n+1;o[n]:=o[j]; end; end; with mm do begin for j:=1 to n do begin dt[j]:=-o[j].z/k.g.z; o[j]:=o[j]+(k.g*dt[j]); end; end; mm:=jiao(na,mm); if mm.n<3 then continue; q[i].new(mm); inc(mm,dz); k.g.z:=-k.g.z; k.g:=ro(pj,k.g); k.p:=ro(pj,mm); work(k,lim-1); end; end; begin assign(input,'box10.in');reset(input); assign(output,'box10.out');rewrite(output); readln(m,n,lim); for i:=1 to m do with dd[i] do read(x,y,z); for i:=1 to n do with a[i] do begin read(n); for j:=1 to n do begin read(k);o[j]:=dd[k]; end; with d do begin x:=o[2]-o[1]; z:=x*(o[3]-o[1]); y:=x*z; x:=x/len(x); y:=y/len(y); z:=z/len(z); end; end; with f.p do begin n:=3; for i:=1 to 3 do with o[i] do read(x,y,z); end; with f.g do read(x,y,z); work(f,lim); for i:=1 to n do ans:=ans+q[i].cal; writeln(ans:0:2); close(input);close(output); end. 

你可能感兴趣的:(c,function,object,input,output)