[UVA10270]拼接正方形解题报告
来源:互联网 发布:linux matlab库 编辑:程序博客网 时间:2024/06/10 05:40
这个题做了我好久。。想了好多奇葩剪枝。
我的想法是从第一行开始一行一行往下填。
一个比较简单的剪枝是处理出当前剩余面积的最小代价,如果加上最小代价都大于等于当前最优解了,那么就直接减掉就好了。它是可以DP出来的,显然
但是它与实际情况相差实在太大了,所以我们试图估算它的剩余最小代价;考虑当我们将要填下一行的时候我们知道这时的图形是一个正方形然后从上到下挖去一些矩形形成的,所以我们把这些矩形分裂出来,因为它们要填正方形的话是至少需要[矩形的面积/矩形的宽的平方]个正方形的,所以我们加上这个玩意儿。然后再把剩余面积都弄到一起做f函数,这个做起来非常麻烦,还需要用到单调栈,我写了半天。。。
面对合数的局面,如果使用迭代加深的情况,是可以很快的,因为对于合数而言,其最优解需要的正方形是相当少的,也很有规律。
但是问题在于37、41、43、47这4个大素数,这也是本题最大的难点。。我一直不能很好地处理它们。。也一直没有想出更好的剪枝。而如果有迭代加深的话反而不如直接搜。观察到从19到31每个素数之间最多相差1,而31需要15,所以我推测47应该。。应该不会超过20。
然后我弃疗打算让它们跑上几个小时,然后去看标算。。结果我发现37的只花了5min就跑出了与31的情况一样的15个正方形的解,这绝对是最优解了!而题解也是跑了半个小时才跑出来这几块硬骨头的。。
这是我的代码。。
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#include<ctime>using namespace std;int f[2505];int N,M;bool a[55][55];int r[55][55],d[55][55];struct AS{ int len; int x,y;}tmp[2505],ans[2505];struct SS{ int y,high;}stack[55];inline void dfs(int x,int y,int sum,int S){ //cout<<"dfs("<<x<<","<<y<<","<<sum<<","<<S<<")\n"; if(sum+f[S]>=M)return; if(x<N){ int tot=0; for(int i=1;i<=N;++i) if(a[x+1][i])i+=r[x+1][i]; else{ while(i<N&&!a[x+1][i])++i; ++tot; } if(sum+tot>=M)return; } if(x>N){ M=sum; cout<<sum<<endl; memcpy(ans,tmp,sizeof(AS)*M); for(int i=0;i<M;++i)printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].len); return; } else if(y>N){ int i,top=0,tot=0,mid,s=0,tmp; ++x; if(x<=N){ //cout<<"--------"<<x<<"-------\n"; for(i=1;i<=N;++i) if(!a[x][i]){ while(i<N&&!a[x][i+1])++i; stack[top++]=(SS){i,0}; } else{ if(top&&stack[top-1].high<=d[x][i]){ mid=stack[--top].high; if(top) while(top&&stack[top-1].high<=d[x][i]){ --top; if(i-stack[top].y-1<=stack[top].high-mid)tmp=(stack[top].high-mid)/(i-stack[top].y-1); else tmp=0; tot+=tmp; s+=(stack[top].high-mid)*(i-stack[top].y-1)-tmp*(i-stack[top].y-1)*(i-stack[top].y-1); mid=stack[top].high; } else if(d[x][i]!=mid){ if(i-1<=d[x][i]-mid)tmp=(d[x][i]-mid)/(i-1); else tmp=0; tot+=tmp; s+=(d[x][i]-mid)*(i-1)-tmp*(i-1)*(i-1); } } stack[top++]=(SS){i+r[x][i]-1,d[x][i]}; i+=r[x][i]-1; } //puts(""); mid=stack[top-1].high; //printf("top:%d mid:%d tot:%d\n",top,mid,tot); if(top){ while(--top)s+=(stack[top].y-stack[top-1].y)*(N-(x+stack[top].high-1)); s+=stack[top].y*(N-(x+stack[top].high-1)); } else if(N!=x+mid-1)tot+=N/(N-(x+mid-1)); //cout<<sum<<" "<<tot<<"+"<<f[s]<<"("<<s<<")"<<endl; if(sum+tot+f[s]>=M)return; } dfs(x,1,sum,S); } else if(a[x][y])dfs(x,y+r[x][y],sum,S); else{ int i=y; while(i-y+2<N&&i<N&&i<N-x+y&&!a[x][i+1])++i; int j,len=i-y+1; for(i=0;i<len;++i) for(j=0;j<len;++j) a[x+i][y+j]=1; for(;len;--len){ r[x+len][y]=0; for(i=0;i<len;++i)r[x+i][y]=len; for(i=0;i<=len;++i)d[x+i][y]=len-i; tmp[sum]=(AS){len,x,y}; //if(len==1)cout<<"("<<x<<","<<y<<")"<<a[x][y]<<endl; dfs(x,y+len,sum+1,S-len*len); for(i=0;i<len;++i)a[x+len-1][y+i]=0; for(i=0;i<len;++i)a[x+i][y+len-1]=0; } }}int main(){ //freopen("square.in","r",stdin); memset(f,127,sizeof(f)); f[0]=0; for(int i=1;i<=2500;++i){ for(int j=1;j*j<=i;++j)f[i]=min(f[i],f[i-j*j]); ++f[i]; } N=31; { M=20; memset(a,0,sizeof(a)); dfs(1,1,0,N*N); printf("%d\n",N); //printf(out,"%d ",N); printf("%d\n",M); for(int i=0;i<M;++i)printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].len); }}
所以,
①对于这种暴搜题,数据规模有限,那考试的时候大可让自己的代码跑去啊!
②对于题目条件相当苛刻的题,一定要相信自己暴搜!
0 0
- [UVA10270]拼接正方形解题报告
- [HAOI2007] 理想的正方形 解题报告
- haoi2007理想的正方形解题报告
- bzoj 1661: [Usaco2006 Nov]Big Square 巨大正方形 解题报告
- java 解题最大正方形
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- UVa Problem 10270 Bigger Square Please... (拼接正方形)
- UVa Problem 10270 Bigger Square Please... (拼接正方形)
- 遗传算法的入门实现(2):利用正方形拼接firefox
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- java中ArrayList、Vector的使用
- web中table表格点击表头排序
- itoa()和atoi()函数
- java map 排序
- HDU 大数加 - 1250 Hat's Fibonacci
- [UVA10270]拼接正方形解题报告
- java的observer观察者模式
- Unity3d之MonoBehaviour的可重写函数整理
- shell脚本内环境变量问题
- DB2 SQL Error: SQLCODE=-418, SQLSTATE=42610, SQLERRMC=unresolved untyped expression,
- linux 网络配置关闭防火墙相关命令的意思
- A*算法解决迷宫问题
- 关于手机插入外置SD卡不能卸载内置SD卡文件
- C语言指针传递和内存分配