BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / acm-icpc / #1863同步于 2006/7/16
该镜像源已超过 30 天没有更新,可能在源站已被删除。
ACM_ICPC机器人发帖

[讨论]POJ2882解题报告

linandmin
2006/7/16镜像同步0 回复
POJ2882 这道题过得好艰苦,MJ和主号加起来交了三十几次,还是没有最后搞懂。 本题题意,要求在一个1到100的3D空间内放食物,每个食物占一格,给出一系列的食物摆放位置,问最后有几个空的空间(就像围棋中的规则一样,但这题是在3D的空间里下围棋)。 这题有两种解法。先说容易想到的。用并查集。用一个三维数组存放这个放食物的空间,space[N][N][N]。初始值为0。注意,如果被放上食物的点的最大的坐标为max,则这个space[][][]就应该至少用到(max+2)*(max+2)*(max+2)的大小,即相当于在原有空间的外面又套上了一层膜(这是并查集统计的需要,否则答案错误)。然后按输入放食物的点的顺序把放上食物的点赋成1。等输入完了后,这个三维数组就成了一个由数字0和1构成的模拟空间,数组值为0表示此点为空,没有放上食物;为1表示此点放上了食物。接下来就是并查集操作了。遍历这个三维数组,对于每个没有放食物的点(i,j,k),分别检查(i+1,j,k),(i,j+1,k)和(i,j,k+1)这三个方向上的点是不是也没被放上食物。如果这三个方向的点也没被放上食物,则合并(i,j,k)和三个相应的点。遍历了数组后,检查并查集中有多少个集合。设并查集中有count个集合,共有m个点被放上了食物,则最后答案应该是count-m-1。代码如下:注意代码中加注释的那行。 用时:375MS。 #include<stdio.h> #include<iostream> #include<set> #define M 105 using namespace std; int space[M][M][M]; int Mfset[M*M*M],maxi,maxj,maxk; int root(int a) { if(Mfset[a]==a) return a; Mfset[a] = root(Mfset[a]); return Mfset[a]; } bool same(int a,int b) { return root(a)==root(b); } void merge(int a,int b) { if(same(a,b)) return ; Mfset[Mfset[a]]=Mfset[b]; } int value(int i,int j,int k) { return k*(maxi+2)*(maxj+2)+i*(maxj+2)+j+1; } int main() { int ncase,m,i,j,k,x,y,z,ans; scanf("%d",&ncase); while(ncase--) { scanf("%d",&m); for(i=0;i<M;i++) for(j=0;j<M;j++) for(k=0;k<M;k++) space[i][j][k]=1; maxi=maxj=maxk=0;/////////////大家的眼光看过来,看过来(maxi,maxj,maxk分别表示x,y,z方向上最大的坐标) for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); space[x][y][z]=0; if(x>maxi) maxi=x; if(y>maxj) maxj=y; if(z>maxk) maxk=z; } for(i=1;i<=(maxi+2)*(maxj+2)*(maxk+2);i++) Mfset[i]=i; for(i=0;i<=maxi+1;i++) for(j=0;j<=maxj+1;j++) for(k=0;k<=maxk+1;k++) { if(k+1<=maxk+1) if(space[i][j][k+1]!=0 && space[i][j][k]!=0) merge(value(i,j,k+1),value(i,j,k)); if(j+1<=maxj+1) if(space[i][j+1][k]!=0 && space[i][j][k]!=0) merge(value(i,j+1,k),value(i,j,k)); if(i+1<=maxi+1) if(space[i+1][j][k]!=0 && space[i][j][k]!=0) merge(value(i+1,j,k),value(i,j,k)); } for(i=1,ans=0;i<=(maxi+2)*(maxj+2)*(maxk+2);i++) if(Mfset[i]==i) ans++; printf("%d\n",ans-m-1); } return 0; } 理论上如果把加注释的那行改成maxi=maxj=maxk=-50;对结果应该不会有影响,但实践表明,如果把maxi,maxj,maxk的初值改成-2或者小于-2的数时,结果是WA,而把它们初始成0或者1时才会AC。 现在说第二种做法。BFS。 同样用一个space[][][]模拟放食物的空间,这一点和第一种做法一样,也需要在所用空间外面包一层膜。 初始化空间后,就开始遍历整个三维数组。对于每个点,如果这个点没有被放上食物,则以这个点为起点,广度优先地遍历这个点所在的empy space。这个BFS过程就好像一个气球不断地膨胀,直到它遇到四周空间的障碍物才停下。每BFS一次,就相应地把这个被搜索的empy space填满,同时count++。(count的初始值为0,地球人都知道)。最后的答案的count-1。代码如下:同样注意加注释的那行。 用时:500MS。 #include<stdio.h> #include<iostream> #include<queue> #define NN 150 using namespace std; struct node { int x,y,z; }; int space[NN][NN][NN],maxi,maxj,maxk; queue<node> qq; int main() { int ncase,m,i,j,k,x,y,z,ans,ti,tj,tk; node temp; scanf("%d",&ncase); while(ncase--) { scanf("%d",&m); for(i=0;i<NN;i++) for(j=0;j<NN;j++) for(k=0;k<NN;k++) space[i][j][k]=1; maxi=maxj=maxk=0;//////////看过来,看过来………… while(m--) { scanf("%d%d%d",&x,&y,&z); space[x][y][z]=0; if(x>maxi) maxi=x; if(y>maxj) maxj=y; if(z>maxk) maxk=z; } ans=0; for(i=0;i<=maxi+1;i++) for(j=0;j<=maxj+1;j++) for(k=0;k<=maxk+1;k++) { if(space[i][j][k]==0) continue; temp.x=i; temp.y=j; temp.z=k; qq.push(temp); space[temp.x][temp.y][temp.z]=0; while(!qq.empty()) { ti=qq.front().x; tj=qq.front().y; tk=qq.front().z; if(tk+1<=maxk+1 && space[ti][tj][tk+1]!=0) { temp.x=ti; temp.y=tj; temp.z=tk+1; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } if(tk-1>=0 && space[ti][tj][tk-1]!=0) { temp.x=ti; temp.y=tj; temp.z=tk-1; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } if(tj+1<=maxj+1 && space[ti][tj+1][tk]!=0) { temp.x=ti; temp.y=tj+1; temp.z=tk; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } if(tj-1>=0 && space[ti][tj-1][tk]!=0) { temp.x=ti; temp.y=tj-1; temp.z=tk; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } if(ti+1<=maxi+1 && space[ti+1][tj][tk]!=0) { temp.x=ti+1; temp.y=tj; temp.z=tk; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } if(ti-1>=0 && space[ti-1][tj][tk]!=0) { temp.x=ti-1; temp.y=tj; temp.z=tk; qq.push(temp); space[temp.x][temp.y][temp.z]=0; } qq.pop(); } ans++; } printf("%d\n",ans-1); } return 0; } 加注释的原因和第一种方法中出现的问题相同。一旦它们被初始化成-2或者更小的数时,结果就是WA。这个问题我还没想明白,有待大家来解决。
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。