搜索

开篇:

mayan游戏(noip2011 day1 T3)

这道题就是个码量题,老师讲题时淡淡的说写完前两题就花一个半小时了,最后一题不快点打会调不出来,对于一个三个半小时就写两题的蒟蒻来说这。。。。这题就是老师口中的简单题。。。。

这种消数游戏应该每个人都玩过,顾名思义,要消数,所以就要打一个消数函数,消完数,他上面的数又不能在空中飘着(他又不是蜘蛛侠),所以还要打一个下移函数,由于这两天玩洛谷版的2048,得出一个结论,下面的被消掉后,上面的掉下来若能消还会继续消,直到不能消为止,所以还要一个判断有没有消完的函数,这题一看就知道要DFS,所以DFS怎么可以少。

但这题空间就128MB,时间也是巨卡,没有优化怎么能过?DFS这个东西十分神奇,因为他可以莫名其妙的剪枝(剪得你都不认识他了)

然后,你就可以打出这样的代码,一遍不过就重打吧。。。。。

剪枝:

  • 相同颜色可以跳过,这很显然意见。
  • 能往右边搜不要往左边搜,前一个往右边搜就等价于后一个往左边搜。
  • 根据题目的优先度排序,当左边是空块时才考虑左移。
  • 如果有一种颜色有X块,1<=X<=2,一定消不掉不合法
 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=;
int mayan[maxn][maxn];
int xxx;
int ans[maxn][maxn];
int n;
inline int is_clear()
{
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
if(mayan[i][j])
{
return ;
}
}
}
return ;
}
void new_ans(int i,int x,int y,int flag)
{
ans[i][]=x;
ans[i][]=y;
ans[i][]=flag;
}
void fell_down(int x)
{
int tot=-;
for(int i=;i<;i++)
{
if(mayan[x][i])
{
mayan[x][++tot]=mayan[x][i];
}
}
for(int i=tot+;i<;i++)
{
mayan[x][i]=;
}
return ;
}
void clear() {
bool flag = true;
while(flag) {
flag = false;
int temp[][];
memcpy(temp,mayan,sizeof(temp));
for(int i=;i<;i++)
for(int j=;j<;j++)
{
if(i >= && i <= && temp[i][j] && temp[i][j] == temp[i-][j] && temp[i][j] == temp[i+][j]) {
mayan[i][j] = ;
mayan[i-][j] = ;
mayan[i+][j] = ;
flag = true;
}
if(j >= && j <= && temp[i][j] && temp[i][j] == temp[i][j-] && temp[i][j] == temp[i][j+]) {
mayan[i][j] = ;
mayan[i][j-] = ;
mayan[i][j+] = ;
flag = true;
}
} if(!flag)
return;
for(int i=;i<;i++)
fell_down(i);
}
}
void dfs(int x)
{
if(is_clear()&&x==n)
{
for(int i=;i<=x;i++)
{
cout<<ans[i][]<<" "<<ans[i][]<<" "<<ans[i][]<<endl;
xxx=;
}
exit();
}
if(x>=n)
{
return ;
}
int temp[][];
memcpy(temp,mayan,sizeof(temp));
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
if(!mayan[i][j])
{
continue;
}
if(i!=)
{
swap(mayan[i][j],mayan[i+][j]);
fell_down(i);
fell_down(i+);
clear();
new_ans(x+,i,j,);
dfs(x+);
new_ans(x+,,,);
memcpy(mayan,temp,sizeof(mayan));
}
if(i&&!mayan[i-][j])
{
swap(mayan[i][j],mayan[i-][j]);
fell_down(i);
fell_down(i - );
clear();
new_ans(x+,i,j,-);
dfs(x + );
new_ans(x+,,,);
memcpy(mayan,temp,sizeof(mayan));
}
} }
}
int main()
{
cin>>n;
for(int i=;i<;i++)
{
int p=;
do
{
cin>>mayan[i][p];
p++;
}while(mayan[i][p-]!=);
}
dfs();
if(xxx!=)
{
cout<<-<<endl;
}
}

拓展:剪枝

  • DFS专用,BFS就不用想了。
  • 可行性剪枝:如果已经判断这下面的都不合法,就可以剪枝。
  • 最优性剪枝:如果下面的答案一定不会比当前更优,剪枝
  • 搜索的顺序对剪枝会有很大影响。

一些好到无话可说的好题目:

  1. NOIP2015 斗地主
  • 如果当前的出牌数已经超过了最优的ans,剪枝(最优性剪枝)
  • 搜索顺序:先顺子,之后就不用记录牌的大小了,只要记录张数有1,2,3,4的分别有几种就可以了。
  • 之后先打牌数多的,先打四带二,再打三带一,也就是说一旦打出三代一,以后就不可能打出四带二了。
  • 每次搜索开始时,用当前的出牌数加上不同点数的牌的数量更新ans。

代码

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int ans=0x7fffffff;
int n,m,sum[];
int T;
void DFS(int x)
{
if(x>=ans)//˳×Ó
{
return ;
}
int k=;//µ¥Ë³×Ó
for(int i=;i<=;i++)
{
if(sum[i]==)
{
k=;
}
else
{
k++;
if(k>=)
{
for(int j=i;j>=i-k+;j--)
{
sum[j]--;
}
DFS(x+);
for(int j=i;j>=i-k+;j--)
{
sum[j]++;
}
}
}
}
k=;//˫˳×Ó
for(int i=;i<=;i++)
{
if(sum[i]<=)
{
k=;
}
else
{
k++;
if(k>=)
{
for(int j=i;j>=i-k+;j--)
{
sum[j]-=;
}
DFS(x+);
for(int j=i;j>=i-k+;j--)
{
sum[j]+=;
}
}
}
}
/*k=0;//Èý˳×Ó
for(int i=3;i<14;i++)
{
if(sum[i]<=2)
{
k=0;
}
else
{
k++;
if(k>=2)
{
for(int j=i;j>=i-k+1;j--)
{
sum[j]-=3;
}
DFS(x+1);
for(int j=i;j>=i-k+1;j--)
{
sum[j]+=3;
}
}
}
}*/
for(int i=;i<=;i++)//´øÅÆ
{
if(sum[i]<=)
{
if(sum[i]<=)
{
continue;
}
sum[i]-=;
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]--;
DFS(x+);
sum[j]++;
}
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]-=;
DFS(x+);
sum[j]+=;
}
sum[i]+=;
}
else
{
sum[i]-=;
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]--;
DFS(x+);
sum[j]++;
}
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]-=;
DFS(x+);
sum[j]+=;
}
sum[i]+=;
sum[i]-=;
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]--;
for(int k=;k<=;k++)
{
if(sum[k]<=||k==j)
{
continue;
}
sum[k]--;
DFS(x+);
sum[k]++;
}
sum[j]++;
}
for(int j=;j<=;j++)
{
if(sum[j]<=||j==i)
{
continue;
}
sum[j]-=;
for(int k=;k<=;k++)
{
if(sum[k]<=||j==k)
{
continue;
}
sum[k]-=;
DFS(x+);
sum[k]+=;
}
sum[j]+=;
}
sum[i]+=; }
}
for(int i=;i<=;i++)
{
if(sum[i])
{
x++;
}
}
ans=min(ans,x);
}
int main()
{
cin>>T>>n;
while(T--)
{
ans=0x7fffffff;
int x,y;
memset(sum,,sizeof(sum));
for(int i=;i<=n;i++)
{
cin>>x>>y;
if(x==)
{
sum[]++;
}
else
if(x==)
{
sum[]++;
}
else
{
sum[x]++;
}
}
//cout<<ans<<endl;
DFS();
cout<<ans<<endl;
}
return ;
}

2.切蛋糕(IOI 1999)

这是道名题啊!!!!!

IOI啊!!!!

不过也确实时20年前的题目了,要是放到现在,那想游客这样的大佬也不会天天说AKIOI了,但在当年确实怪难,那剪枝,鬼畜。

  • 搜索顺序 :从最下面一层开始,一层一层向上搜,枚举最下面的半径和高度最大。
  • 以算好的答案(最小面积)减去蛋糕当前层以下的总面积若小于上面所能构成的最小面积,就剪枝(最优性剪枝)
  • 总体积减去当前层以下的总体积小于上面所能构成的最小体积,剪枝(可行性剪枝)
 #include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
const int maxn=;
int roun[maxn];
int high[maxn];
int n,m;
int minn=0x7fffffff;
void dfs(int x,int y,int k,int z)
{
if(y<)
{
//cout<<111111<<endl;
return ;
}
if(k>=minn)
{
// cout<<22222<<endl;
return ;
}
if(x>m+)
{
//cout<<33333<<endl;
return ;
}
if(y==&&x==m+)
{
k=k+roun[]*roun[];
if(k<minn)
{
minn=k;
}
//cout<<44444<<endl;
return ;
}
if(k+z+roun[]*roun[]>minn)
{
//cout<<55555<<endl;
return ;
}
if(y-(roun[x-])*(roun[x-])*(high[x-])*z>)
{
//cout<<6666<<endl;
return ;
}
for(int i=roun[x-]-;i>=z;i--)
{
for(int j=high[x-]-;j>=z;j--)
{
if(y-i*j*i>=&&x+<=m+)
{
roun[x]=i;
high[x]=j;
dfs(x+,y-i*i*j,k+(*i*j),z-);
high[x]=;
roun[x]=;
//cout<<111111<<endl; }
}
}
}
int main()
{
cin>>n>>m;
roun[]=(int )sqrt(n);
high[]=(int )sqrt(n);
dfs(,n,,m);
if(minn==0x7ffffff)
{
cout<<""<<endl;
}
else
{
cout<<minn<<endl;
} return ;
}

3.小木棍(加强版)

这是一个好题目 ,那个天天AKIOI的游客(因为是机房大佬,所以不得不膜)竟然运用运动会的时间,花了一下午没打出来,真好奇他当时有没有对电脑进行了某种报复行为。。。。

  • 暴力思路,一个一个枚举长度x,看能不能填满sum/x根木棍。
  • 剪枝1:X必须是sum的因数,且X>=maxlen。
  • 剪枝2:将木棍降序排列,优先填更长的。
  • 剪枝3:开始搜索一根新木棒时,如果用第一根未填过的木棍填充就已经失败,那一定会失败。
  • 剪枝4:多根木棍一样时,一根失败,后面全部跳过。
  • 剪枝5:因为答案限制了一个最长值,这一个东西卡死了好多书上的标称。
  • 后话:这题蓝书上的程序过不了,本来机房大佬都做好了变棕的准备,然后发现过不了。。。。
 #include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
int minn,maxx;
int n,m;
const int maxn=1e6+;
int tim[maxn];
int tot,cnt;
void dfs(int ans,int sum,int flag,int p)
{
if(ans==)
{
cout<<flag<<endl;
exit();
}
if(sum==flag)
{
dfs(ans-,,flag,maxx);
return ;
}
for(int i=p;i>=minn;i--)
{
if(i+sum<=flag&&tim[i])
{
tim[i]--;
dfs(ans,sum+i,flag,i);
tim[i]++;
if(sum==||i+sum==flag)
{
break;
}
} }
return ;
}
int main()
{
cin>>n;
minn=n;
int m;
while(n--)
{
cin>>m;
if(m<=)
{
tot++;
tim[m]++;
cnt+=m;
maxx=max(maxx,m);
minn=min(minn,m);
} }
m=cnt>>;
for(int i=maxx;i<=m;i++)
{
if(cnt%i==)
{ dfs(cnt/i,,i,maxx);
}
}
cout<<cnt<<endl;
return ;
}

不得不说满眼的绿色还挺舒服的。。。。

DAY 5 搜索的更多相关文章

  1. SQLSERVER走起微信公众帐号已经开通搜狗微信搜索

    SQLSERVER走起微信公众帐号已经开通搜狗微信搜索 请打开下面链接 http://weixin.sogou.com/gzh?openid=oIWsFt-hiIb_oYqQHaBMoNwRB2wM ...

  2. solr_架构案例【京东站内搜索】(附程序源代码)

    注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的. 一:solr服务的端口号.我这里的sol ...

  3. SQLServer地址搜索性能优化例子

    这是一个很久以前的例子,现在在整理资料时无意发现,就拿出来再改写分享. 1.需求 1.1 基本需求: 根据输入的地址关键字,搜索出完整的地址路径,耗时要控制在几十毫秒内. 1.2 数据库地址表结构和数 ...

  4. HTML5轻松实现搜索框提示文字点击消失---及placeholder颜色的设置

    在做搜索框的时候无意间发现html5的input里有个placeholder属性能轻松实现提示文字点击消失功能,之前还傻傻的在用js来实现类似功能... 示例 <form action=&quo ...

  5. bzoj1079--记忆化搜索

    题目大意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得 ...

  6. bzoj3208--记忆化搜索

    题目大意: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目.    我们可以把风景区看作一个n*n的地图,每个点有它的初始高度,滑雪只能从高处往低处滑[严格大于] ...

  7. Android中通过ActionBar为标题栏添加搜索以及分享视窗

    在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果.Action ...

  8. 一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)

    前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做 ...

  9. Go语言实战 - 我需要站内搜索

    山坡网的用户抱怨"为什么搜索'二鬼子李富贵'找不到'二鬼子汉奸李富贵'?我用百度搜都能找到." 当时我就滴汗了,用户说的有道理,应该要能搜索到. 之前的方案很简单,用户输入的字串会 ...

  10. Entity Framework 6 Recipes 2nd Edition(13-4)译 -> 有效地创建一个搜索查询

    问题 你想用LINQ写一个搜索查询,能被转换成更有效率的SQL.另外,你想用EF的CodeFirst方式实现. 解决方案 假设你有如下Figure 13-6所示的模型 Figure 13-6. A s ...

随机推荐

  1. 分库分表(4) ---SpringBoot + ShardingSphere 实现分表

    分库分表(4)--- ShardingSphere实现分表 有关分库分表前面写了三篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理论) 3.分库 ...

  2. Unknown column 'user_id' in 'where clause'

    mapper位置报错Unknown column 'user_id' in 'where clause' 可能是数据库中的字段user_id包含空格

  3. STM32进阶之串口环形缓冲区实现

    队列的概念 在此之前,我们来回顾一下队列的基本概念: 队列 (Queue):是一种先进先出(First In First Out ,简称 FIFO)的线性表,只允许在一端插入(入队),在另一端进行删除 ...

  4. python编程基础之二十二

    字典:字典属于可变对象,但是不属于序列,内部是通过哈希方式存储的,内部保存的是一个个键值对key:value 字典的键是唯一的, 字典查找速度比较快 d1 = {}  #括号里面用键值对表示 d2 = ...

  5. spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理

    @Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供 ...

  6. tesseract 测试样例

    该图片的链接为https://raw.githubusercontent.com/Python3WebSpider/TestTess/master/image.png,可以直接保存或下载. 首先用命令 ...

  7. sqlmap实战-1

    sqlmap实战-1 检测和利用sql注入 python2 sqlmap.py -u "[URL_SQL注入点]" [--batch] --batch:自动选择sqlmap默认的选 ...

  8. SpringCloud教程二:Ribbon(Finchley版)

    在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...

  9. USART_FLAG_TXE和USART_FLAG_TC

    在串口数据发送操作中,代码一般是这样写的: void USART_SendByte(USART_TypeDef* USARTx, uint8_t Data) { while(USART_GetFlag ...

  10. Unity 登录白屏或者黑屏

    如果有一天,突然,你的Unity抽风了,登录界面白屏或者黑屏,不要急着重装.我重装了3次,第四次我再也忍不住了,终于出手了. 找到 C:\Users\hasee\AppData\Roaming\Uni ...