DAY 5 搜索
搜索
开篇:
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就不用想了。
- 可行性剪枝:如果已经判断这下面的都不合法,就可以剪枝。
- 最优性剪枝:如果下面的答案一定不会比当前更优,剪枝
- 搜索的顺序对剪枝会有很大影响。
一些好到无话可说的好题目:
- 如果当前的出牌数已经超过了最优的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 搜索的更多相关文章
- SQLSERVER走起微信公众帐号已经开通搜狗微信搜索
		SQLSERVER走起微信公众帐号已经开通搜狗微信搜索 请打开下面链接 http://weixin.sogou.com/gzh?openid=oIWsFt-hiIb_oYqQHaBMoNwRB2wM ... 
- solr_架构案例【京东站内搜索】(附程序源代码)
		注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的. 一:solr服务的端口号.我这里的sol ... 
- SQLServer地址搜索性能优化例子
		这是一个很久以前的例子,现在在整理资料时无意发现,就拿出来再改写分享. 1.需求 1.1 基本需求: 根据输入的地址关键字,搜索出完整的地址路径,耗时要控制在几十毫秒内. 1.2 数据库地址表结构和数 ... 
- HTML5轻松实现搜索框提示文字点击消失---及placeholder颜色的设置
		在做搜索框的时候无意间发现html5的input里有个placeholder属性能轻松实现提示文字点击消失功能,之前还傻傻的在用js来实现类似功能... 示例 <form action=&quo ... 
- bzoj1079--记忆化搜索
		题目大意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得 ... 
- bzoj3208--记忆化搜索
		题目大意: 花花山峰峦起伏,峰顶常年被雪,Memphis打算帮花花山风景区的人员开发一个滑雪项目. 我们可以把风景区看作一个n*n的地图,每个点有它的初始高度,滑雪只能从高处往低处滑[严格大于] ... 
- Android中通过ActionBar为标题栏添加搜索以及分享视窗
		在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果.Action ... 
- 一步步开发自己的博客  .NET版(5、Lucenne.Net 和 必应站内搜索)
		前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ... 
- Go语言实战 - 我需要站内搜索
		山坡网的用户抱怨"为什么搜索'二鬼子李富贵'找不到'二鬼子汉奸李富贵'?我用百度搜都能找到." 当时我就滴汗了,用户说的有道理,应该要能搜索到. 之前的方案很简单,用户输入的字串会 ... 
- Entity Framework 6 Recipes 2nd Edition(13-4)译 -> 有效地创建一个搜索查询
		问题 你想用LINQ写一个搜索查询,能被转换成更有效率的SQL.另外,你想用EF的CodeFirst方式实现. 解决方案 假设你有如下Figure 13-6所示的模型 Figure 13-6. A s ... 
随机推荐
- 做高逼格程序员之说走就走的「Linux To Go 」
			简介:想拥有一个Linux,在自己的电脑上安装双系统太麻烦.想和WTG一样,随插随用. 使用LTG的好处 安装.修复系统:配置好后的Linux系统极其强大. 工作中我们同样可以使用这个系统,回到家里插 ... 
- 利用npm安装/删除/查看包信息
			查看远程服务器上的包的版本信息 npm view webpack version //查看npm服务器上包webpack的最新版本 npm view webpack versions //查看服务器上 ... 
- powershell(一)
			Windows powershell是一种命令行外壳程序和脚本环境,它内置在win7以上版本的操作系统中,使命令行用户和脚本编写者可以利用.NET Framework的强大功能.powershell程 ... 
- main(argc, char *argv[])
			#include<stdio.h> int main(int argc, char *argv[]) { int i; ;i<argc;i++) { printf("arg ... 
- Github桌面端安装慢问题
			失败截图: 原因是某些域名被墙,所以这里想安装快的话还是得翻墙.如何翻墙请自行百度. 如果翻墙还是很慢,请参考网上大神文章:https://www.yaozeyuan.online/2015/10/0 ... 
- PHP reset
			1.函数的作用:重置数组内部指针,并返回第一个元素 2.函数的参数: @param array $array 3. 例子一: <?php $arr1 = []; $arr2 = [false, ... 
- CF543A Writing Code
			题目描述 Programmers working on a large project have just received a task to write exactly m m m lines o ... 
- Cocos2d-x 学习笔记(15.3) EventDispatcher DirtyFlag 脏标记
			1. 定义 用枚举定义脏标记的4种类型. enum class DirtyFlag { NONE = , FIXED_PRIORITY = << , SCENE_GRAPH_PRIORIT ... 
- ElasticSearch安装及使用
			ElasticSearch安装及使用 ELK由Elasticsearch.Logstash和Kibana三部分组件组成. Elasticsearch 是个开源分布式搜索引擎,它的特点有:分布式,零配置 ... 
- qt读取文本
			直接 代码: // lyy : 2016/8/26 16:40:11 说明:读取文本 bool FileOpeartion:: GetTheTextContent (const QString str ... 
