| ||||||||||
| 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 | |||||||||
Re:数据太弱,暴力搜索不剪枝AC!In Reply To:数据太弱,暴力搜索不剪枝AC! Posted by:boycott at 2008-10-22 22:42:19 > 10
> 21 16 5 7 2 4 8 9 4 2 3 2 4 2 9 6 4 4
> 28 16 10 10 7 3 5 9 10 3 8 5 7 7 5 7 1 7
> 13 11 1 2 2 8 1 2 3 7 1 4 4
> 23 16 1 7 5 8 5 10 9 2 1 4 2 6 3 1 8 7
> 26 16 3 7 10 9 8 3 1 9 6 6 8 2 10 1 5 4
> 21 16 6 5 10 4 2 3 4 7 7 2 3 3 1 1 7 8
> 18 14 2 6 3 1 2 3 9 9 4 5 7 2 1 2
> 15 12 3 1 3 1 8 1 5 1 6 2 6 3
> 22 15 2 6 8 5 4 7 9 9 4 5 4 3 6 3 4
> 22 14 4 1 6 7 9 1 7 3 10 8 1 6 5 4
>
> HUTUTU!
> HUTUTU!
> HUTUTU!
> KHOOOOB!
> KHOOOOB!
> KHOOOOB!
> KHOOOOB!
> HUTUTU!
> HUTUTU!
> KHOOOOB!
>
> 基本思路就是从左到右,从上往下,枚举每个小正方形放进去。
> #include<iostream>
> using namespace std;
> int c[11],d[41],s,n,sum;
> bool ok;
> void dfs(int a)
> {
> int i,j,put,p;
> bool f;
> if(a==n) {ok=true;exit;}
> for(i=1,put=41;i<=s;i++)
> if(d[i]<put) {put=d[i];p=i;}
> for(i=10;i>=1;i--)
> if(c[i]>0 && put+i-1<=s && p+i-1<=s)
> {
> for(j=p,f=true;j<=p+i-1;j++)
> if(d[j]>put) {f=false;break;}
> if(f)
> {
> for(j=p;j<=p+i-1;j++) d[j]+=i;
> c[i]--;
> dfs(a+1);
> c[i]++;
> for(j=p;j<=p+i-1;j++) d[j]-=i;
> }
> }
> }
> int main()
> {
> int t,it,i,tp;
> cin>>t;
> for(it=1;it<=t;it++)
> {
> cin>>s>>n;
> memset(c,0,sizeof(c));
> for(i=1;i<=40;i++) d[i]=1;
> sum=0;
> for(i=1;i<=n;i++)
> {
> cin>>tp;
> c[tp]++;
> sum+=tp*tp;
> }
> if(sum!=s*s) ok=false;
> else {ok=false;dfs(0);}
> if(ok) cout<<"KHOOOOB!"<<endl;
> else cout<<"HUTUTU!"<<endl;
> }
> system("pause");
> return 0;
> }
代码确实不错。。感觉并不是不剪枝。。
for(i=10;i>=1;i--)
if(c[i]>0 && put+i-1<=s && p+i-1<=s)
这里就直接吧相同的给处理掉了。。
感觉巧妙之处就是把相同的蛋糕放在一起计数了。。否则还得排序。。然后在处理的时候比较来剪掉相同的。。
在网上找到一个更方便读的。。还有注释。。搞了一上午。。算明白了。。
尊重作者:http://cool8511.blog.hexun.com/32069650_d.html
#include <stdio.h>
#include <memory.h>
int cakeside,piecenum,pieces[11];
//fillednum stand for the nums had filled
bool fill(int fillednum,int* used)
{
//如果已填的个数等于需求的蛋糕个数则表示刚好
if(fillednum==piecenum)
return true;
int i,j,minusedrow=41,nowcol=0;
//寻找未填的行数最小的那列
for(i=1;i<=cakeside;i++)
{
if(used[i]<minusedrow)
{
minusedrow = used[i];
nowcol = i;
}
}
//从行数最小的那列开始,从大到小搜索能填入的蛋糕
for(i=10;i>0;--i)
{
if(pieces[i]>0 && i+minusedrow<=cakeside+1 && i+nowcol<=cakeside+1)
{
bool flag=true;
//判断连续的区域是否能放下当前蛋糕
for(j=nowcol;j<nowcol+i;j++)
{
if(used[j]>minusedrow)
{
flag=false;
break;
}
}
if(flag)
{
//能放下则更新蛋糕所在的列的已填行数
for(j=nowcol;j<nowcol+i;j++)
used[j] += i;
//当前大小蛋糕数减一
pieces[i]--;
//继续切下一块蛋糕
if(fill(fillednum+1,used))
return true;
//到这说明上面方案不可行,回溯,不能切当前大小的蛋糕
pieces[i]++;
for(j=nowcol;j<nowcol+i;j++)
used[j] -= i;
}
}
}
return false;
}
int main()
{
int ncase,i,j;
scanf("%d",&ncase);
while(ncase>0)
{
--ncase;
int sum=0;
int pieceside;
scanf("%d %d",&cakeside,&piecenum);
memset(pieces,0,sizeof(pieces));
//记录各不同大小的蛋糕个数,大小范围在1-10之间
for(i=0;i<piecenum;++i)
{
scanf("%d",&pieceside);
//大小为pieceside的个数
pieces[pieceside]++;
sum += pieceside*pieceside;
}
if(sum!=cakeside*cakeside)
{
printf("HUTUTU!\n");
continue;
}
bool IsWaste=true;
//used[i]记录的是第i列还没填的那行
int used[41];
for(i=1;i<=40;i++) used[i]=1;
//fill表示从第几块蛋糕开始填是否能刚好填满所有蛋糕
IsWaste = !fill(0,used);
if(IsWaste)
printf("HUTUTU!\n");
else
printf("KHOOOOB!\n");
}
return 0;
}
PS:感觉在网页看代码太乱。。ctrl+v到notepad2看着舒服。。嘿嘿。。
Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator