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 ...
随机推荐
- 基于Influxdb对InfluxDBResultMapper的一点扩展
理想很饱满,现实很骨感. 由于业务需要"灵活可配置"的功能需求,在使用java开发Influxdb查询功能的时候,遇到了一个问题,Measurement注解的名称有可能需要动态变化 ...
- HTML5 + WebGL 实现的垃圾分类系统
前言 垃圾分类,一般是指按一定规定或标准将垃圾分类储存.分类投放和分类搬运,从而转变成公共资源的一系列活动的总称.分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用.垃圾在分类储存阶段属于公众的私 ...
- MQTT介绍与使用
物联网是新一代信息技术的重要组成部分,也是“信息化”时代的重要发展阶段.其英文名称是:“Internet of things(IoT)”.顾名思义,物联网就是物物相连的互联网.这有两层意思:其一,物联 ...
- C#输入中文实现转拼音首字母(亲测,字库不全)
public string GetPYString(string str) { string tempStr = ""; foreach (char c in str) { if ...
- 《深入理解Java虚拟机》-----第13章 线程安全与锁优化
概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...
- Java SPI、servlet3.0与@HandlesTypes源码分析
关于Java SPI与servlet3.0的应用,这里说的很精炼,链接地址如下. https://blog.csdn.net/pingnanlee/article/details/80940993 以 ...
- Linux本地内核提权漏洞复现(CVE-2019-13272)
Linux本地内核提权漏洞复现(CVE-2019-13272) 一.漏洞描述 当调用PTRACE_TRACEME时,ptrace_link函数将获得对父进程凭据的RCU引用,然后将该指针指向get_c ...
- 设置H5页面文字不可复制
* { moz-user-select: -moz-none; -moz-user-select: none; -o-user-select: none; -khtml-user-select: no ...
- 用Java JMC控制台分析线程阻塞原因
问题 今天在玩dianping-CAT框架时,发现请求某个页面的时候,发生了阻塞.浏览器得不到响应. 环境 本地Tomcat 8 , Windows 系统. 解决 启动jmc 控制台,找到BLOCKE ...
- 3D切割轮播图
预览图: 实现原理:将图片切割构建一个和ul(电脑屏幕)同一个轴的立方体,利用延时旋转实现切割效果 知识点:transform-style属性(必须搭配transform属性使用) 值 描述 flat ...