USACO 6.3 章节 你对搜索和剪枝一无所知QAQ

emmm........很久很久以前 把6.2过了 所以emmmmmm 直接跳过 ,从6.1到6.3吧

Fence Rails

题目大意

N<=50个数A1,A2...

1023个数,每个数数值<=128,B

问 A 们能拆分成多少个B,求最多的个数

样例 解释

A:
30=30
40=18+19+3
50=15+16+17+2
25=24
B:
15 (ok)
16 (ok)
17 (ok)
18 (ok)
19 (ok)
20
21
25
24 (ok)
30 (ok)

所以最多7个

题解

首先 如果对B 排序,假设最优个数为k个

显然 如果k个可行,那么排序后的B 的前k个可行

又 如果k个可行那么k-1个可行,综上又满足二分

先 sort+二分+从大到小放b (第4个点就超时了)

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)using namespace std;const string filename = "fence8";void usefile(){freopen((filename+".in").c_str(),"r",stdin);freopen((filename+".out").c_str(),"w",stdout);
}int n;
int a[100];
int la[100];
int suma;
int R;
int r[1100];
int sumr[1100];int dfs(int idx){per(i,0,n){if(a[i] < r[idx]){return false;}if(a[i] ==  a[i+1] && la[i] == la[i+1]){continue;}if(la[i] < r[idx]){continue;}if(idx == 0){return true;}la[i] -= r[idx];int ret = dfs(idx-1);la[i] += r[idx];if(ret){return true;}}return false;
}bool test(int idx){if(sumr[idx] > suma)return false;return dfs(idx);
}int main(){usefile();scanf("%d",&n);rep(i,0,n){scanf("%d",a+i);}rep(i,0,n){la[i]=a[i];suma += a[i];}sort(a,a+n);scanf("%d",&R);rep(i,0,R){scanf("%d",r+i);}sort(r,r+R);if(r[0] > a[n-1]){cout<<0<<endl;return 0;}sumr[0]=r[0];rep(i,1,R){sumr[i]=sumr[i-1]+r[i];}int l=0,r=R;while(l+1<r){int mid = (l+r)/2;if(test(mid)){l = mid;}else{r = mid;}}cout<<l+1<<endl;return 0;
}

对B 的枚举过程加了相同长度的枚举优化 tle 5

int dfs(int idx,int stn = n){per(i,0,stn){if(a[i] < r[idx]){return false;}if(a[i] ==  a[i+1] && la[i] == la[i+1]){continue;}if(la[i] < r[idx]){continue;}if(idx == 0){return true;}la[i] -= r[idx];int ret;if(r[idx] == r[idx+1]){ret = dfs(idx-1,i+1);}else{ret = dfs(idx-1);}la[i] += r[idx];if(ret){return true;}}return false;
}

增加了 无效残余木料 AC

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)using namespace std;const string filename = "fence8";void usefile(){freopen((filename+".in").c_str(),"r",stdin);freopen((filename+".out").c_str(),"w",stdout);
}int n;
int a[100];
int la[100];
int suma;
int R;
int r[1100];
int sumr[1100];int dfs(int idx,int stn = n){if(suma < sumr[idx]){return false;}per(i,0,stn){if(a[i] < r[idx]){return false;}if(a[i] ==  a[i+1] && la[i] == la[i+1]){continue;}if(la[i] < r[idx]){continue;}if(idx == 0){return true;}la[i] -= r[idx];suma-=r[idx];bool predel = la[i] < r[0];if(predel){suma -= la[i];}int ret;if(idx > 0 && r[idx-1] == r[idx]){ret = dfs(idx-1,i+1);}else{ret = dfs(idx-1);}if(predel){suma += la[i];}suma+=r[idx];la[i] += r[idx];if(ret){return true;}}return false;
}bool test(int idx){if(sumr[idx] > suma)return false;return dfs(idx);
}int main(){usefile();scanf("%d",&n);rep(i,0,n){scanf("%d",a+i);}rep(i,0,n){la[i]=a[i];suma += a[i];}sort(a,a+n);scanf("%d",&R);rep(i,0,R){scanf("%d",r+i);}sort(r,r+R);if(r[0] > a[n-1]){cout<<0<<endl;return 0;}sumr[0]=r[0];rep(i,1,R){sumr[i]=sumr[i-1]+r[i];}int l=0,r=R;while(l+1<r){int mid = (l+r)/2;if(test(mid)){l = mid;}else{r = mid;}}cout<<l+1<<endl;return 0;
}

综上 二分+暴搜+减枝+处理顺序贪心

Cryptcowgraphy

题目大意

一个字符串能否通过 正数次操作使得变为

Begin the Escape execution at the Break of Dawn

一次操作: 选取 ...C...O...W...,把C->O的字符串和O->W的字符串交换,然后去掉这三个选中C,O,W

题解

显然 特判打表

我们已经知道 目标串 和 起始串

所以如果可行,那么 个数关系有C=O=W =(len(起始串)-len(目标串))/3,所以预先筛选的一个优化是,统计各个字符的个数,和目标串进行比较

所以 当比较是可能时,答案要么0 0,要么 1 字母C 的个数

我们可以优化的点

  1. 字母个数统计
  2. 被C O W 分割的在任意时刻是 目标串的子串
  3. 搜索顺序先O
  4. 字符串hash [注意 这个方法 如果你是在打cf,那么很可能被hack

注意输入是一行....所以不要scanf %s

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)using namespace std;const string filename = "cryptcow";void usefile(){freopen((filename+".in").c_str(),"r",stdin);freopen((filename+".out").c_str(),"w",stdout);
}
const char Goal[] = "Begin the Escape execution at the Break of Dawn";
const int Mod = 999983;char s[110];
int ans, cnt;
bool hsh[Mod];// 删除a b c位置上的, 交换a->b b->c
void work(int a, int b, int c) {static char tmp[100];int len = strlen(s), tot = 0;for(int i = 0; i < a; ++i) {tmp[tot++] = s[i];}for(int i = b + 1; i < c; ++i) {tmp[tot++] = s[i];}for(int i = a + 1; i < b; ++i) {tmp[tot++] = s[i];}for(int i = c + 1; i < len; ++i) {tmp[tot++] = s[i];}tmp[tot] = 0;strcpy(s, tmp);
}int getHash() {int ret = 0, len = strlen(s);for(int i = 0; i < len; ++i) {int num = (s[i]==' ')?1:(isupper(s[i]) ? s[i] - 'A' + 2 : s[i] - 'a' + 28);ret = (ret * 57 + num) % Mod;}return ret;
}bool dfs(int depth) {if(strcmp(s, Goal) == 0) {ans = depth;return true;}int x = getHash();if(hsh[x]) {return false;}hsh[x] = true;++cnt;// 被C O W 分割的 字串应该是Goal的连续子串static char sub[100];int len = strlen(s);int c[20], o[20], w[20];c[0] = o[0] = w[0] = 0;for(int i = 0, j = 0; i < len; ++i) {if(s[i] == 'C' || s[i] == 'O' || s[i] == 'W') {if(s[i] == 'C') {c[++c[0]] = i;}if(s[i] == 'O') {o[++o[0]] = i;}if(s[i] == 'W') {w[++w[0]] = i;}sub[j] = 0;if(!strstr(Goal, sub)) { //return false;}j = 0;}else {sub[j++] = s[i];}}// C = W = Oif(o[0] != c[0] || o[0] != w[0] || w[0] != c[0]) {return false;}char pre[100];strcpy(pre, s); // 递归暂存// 查找顺序 先找Orep(j,1,o[0]+1){per(k,1,w[0]+1){if(w[k] < o[j])break;rep(i,1,c[0]+1){if(c[i] > o[j])break;work(c[i], o[j], w[k]);bool ret = dfs(depth + 1);if(ret){return true;}if(cnt > 200000) { // ............................return false;}strcpy(s, pre);}}}return false;
}int main() {usefile();cin.getline(s,100);// scanf("%s",s);int ret = dfs(0);printf("%d %d\n", ret, ans);return 0;
}

Cowcycles

题目大意

25 <= F1 < F2 <= 80

[F1,F2]范围找[1,5]个数f1,f2..

5 <= R1 < R2 <= 40

[R1,R2]范围找[1,10]个数r1,r2..

ratio(i,j) = fi/rj

max ratio/min ratio >= 3的限制下

把所有ratio(i,j)排序,最小化 排序后数组相邻值 的差 的方差

求具体方案

题解

ratio(i1,j1)/ratio(i2,j2) = i1*j2/i2*j1

要使这个值的最大值大于3,注意到都是正数,也就是(max(i)*max(j))/(min(i)*min(j)) >= 3

然后因为ratio要先sort,再最小化 差 的方差,就感觉 无路可推,只能暴搜

优化

  1. 默认的限制减枝
  2. 个数少,运算过程相对有序 --> 计算顺序+插入排序
  3. 搜一搜初中的方差变形公式,省掉最外层的1/n 有只用比较sum{平方}+(sum{}平方)/n

注意 以下代码过了USACO 但是有潜在风险,浮点数比大小!! 如果是打cf,可能会被叉

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)using namespace std;const string filename = "cowcycle";void usefile(){freopen((filename+".in").c_str(),"r",stdin);freopen((filename+".out").c_str(),"w",stdout);
}int s1[20],s2[20];
int ans1[20],ans2[20];
int F,F1,F2;
int R,R1,R2;
int cnt;
double rate[100],diff[100];
double minvf=10000000;void count(){int k=0;double sum=0,avg,vf=0,sumf=0,p;// 数据量小 采用插入排序rep(i,0,F){rep(j,0,R){p=(double)s1[i]/s2[j];int l=++k;while (rate[l-1]>=p) {rate[l]=rate[l-1];l--;}rate[l]=p;}}rep(i,1,cnt){diff[i]=rate[i+1]-rate[i];sum+=diff[i];sumf+=diff[i]*diff[i];}avg=sum/(cnt-1);// 相邻值的差的个数 比值的个数少1vf=sumf-sum*avg;if (vf<minvf)  {minvf=vf;memcpy(ans1,s1,sizeof(int)*F);memcpy(ans2,s2,sizeof(int)*R);}
}// 枚举后齿轮 从w 到R2-R+k+1
void sc2(int k,int w){if (k==R){if (s1[F-1]*s2[R-1]<3*s1[0]*s2[0]) // 题目限制条件剪枝return;count();return;}rep(i,w,R2-R+k+2){s2[k]=i;sc2(k+1,i+1);}
}// 枚举前齿轮 从w到F2-F+k+1
void sc1(int k,int w){if (k==F)  {sc2(0,R1);return;}rep(i,w,F2-F+k+2){s1[k]=i;sc1(k+1,i+1);}
}int main() {usefile();cin>> F >> R >> F1 >> F2 >> R1 >> R2;cnt=F*R;sc1(0,F1);rep(i,0,F){cout << ans1[i] << " \n"[i==F-1];}rep(i,0,R){cout << ans2[i] << " \n"[i==R-1];}return 0;
}

总结

搜索+剪枝,剪究竟要怎么剪

引用一个大佬的话https://apps.topcoder.com/forums/?module=Thread&threadID=669047&start=0&mc=6#1216077

Well, if the optimizations change the complexity of the solution asymptotically, you can quite sure.

Otherwise you can't depend on anything, I think.

重要的是 找到 能明确改变算法 复杂度的剪枝。

反过来分析

第1题

剩余 体积 处理,应该能优化了搜索树的叶节点个数,十分关键

重复体积的搜索处理,优化了枚举体积的次数,对相同体积有多个的情况,从 可放空间数相同个数次方,优化到了???,不知道怎么表示,但是 大量减少了重复枚举是肯定的

从大到小尝试,优化了末端个数?(吗)

第2题

对于错误的预处理 直接一边就否定掉了

目标串的子串是一个有效的大优化,当 在 去掉COW 以后,连接出了 不应该的字符串,可以立刻剪掉,对搜索空间优化大

搜索顺序 先O 还好 大概是常数倍数优化

字符串hash,除了上面的方法,还可以 用其它的 比如神奇的偏移+异或字符串等等, 优化的是很大的字符串比较代价,常数倍数

第3题

基本没有剪枝[题目限制的剪枝是当然

主要靠的是算法使用的性能优化

优化 排序[数量少的时候插入,在具体工程实践中,数量较少的时候 也同样会采取 数组取代map 进行遍历,冒泡取代其它排序 ]

优化 方差运算,目前这样公式变化

默认 n-1次加法 1次除法,算平均数,n次减法,n次乘法,n-1次加法得到结果

优化后 2(n-1)次加法 1次除法,1次减法n+1次乘法,得到结果

假设所有 运算类型时间代价相同,那么算是优化掉了约1/4时间[然而一般来说减法的速度是比乘除快很多,再加上CPU的指令pipeline运算优化,可能影响有,但不大

转载于:https://www.cnblogs.com/CroMarmot/p/11112572.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在基于Spring的Web应用程序中使用Http Session

在基于Spring的Web应用程序中拥有和使用Http会话有多种方法。 这是基于最近项目经验的总结。 方法1 只需在需要的HttpSession中注入即可。 Service public class ShoppingCartService {Autowired private HttpSession httpSession;... }尽管令人惊讶&#xff0c;但由于上述服…

获取当前鼠标的位置以及组件的位置

总结&#xff1a; div如果要触发鼠标事件要加上css样式cusor:pointer。 更多专业前端知识&#xff0c;请上 【猿2048】www.mk2048.com

谷歌推大语言模型VideoPoet:文本图片皆可生成视频和音频

Google Research最近发布了一款名为VideoPoet的大型语言模型&#xff08;LLM&#xff09;&#xff0c;旨在解决当前视频生成领域的挑战。该领域近年来涌现出许多视频生成模型&#xff0c;但在生成连贯的大运动时仍存在瓶颈。现有领先模型要么生成较小的运动&#xff0c;要么在生…

java scala 获取类_在Scala 2.10中获取java.lang.Class [T]的Scala类型

您可以像这样实现您的方法&#xff1a;def getType[T](clazz: Class[T])(implicit runtimeMirror: ru.Mirror) runtimeMirror.classSymbol(clazz).toType然后像这样调用它&#xff1a;implicit val mirror ru.runtimeMirror(getClass.getClassLoader)getType(classOf[String])…

解决ios8下coreData没有NSPersistentContainer的问题

用Xcode8.1默认创建ios app的时候&#xff0c;使用coreData的话&#xff0c;要10.0以上的版本才行。因为NSPersistentContainer只有10.0以上的版本才有&#xff0c;10.0以下的版本是没有的&#xff0c;那怎么办呢&#xff1f;有办法&#xff0c;专为8.0版本加写的INSPersistent…

spring 与 guice 的区别好玩的好法(转)

看下边对于不同社会形态下一个人&#xff08;java对象&#xff0c;调用者&#xff09;需要一把斧子&#xff08;java对象&#xff0c;被调用者&#xff09;的例子&#xff1a;&#xff08;1&#xff09;原始社会时&#xff0c;劳动社会基本没有分工&#xff0c;需要斧子的人&am…

PyCon大会Python主题演讲摘要

PyCon 是全国际最大的以 Python 编程言语 为主题的技能大会。大会由 Python 社区组织&#xff0c;每年举行一次。在大会上&#xff0c;来自国际各地的 Python 用户与中心开发者齐聚一堂&#xff0c;共同同享 Python 国际的新鲜事、Python 言语的应用案例、运用技巧等等内容。 I…

欢迎使用Java 8之前要重温的10个JDK 7功能

Java 8发布已经快一个月了&#xff0c;我敢肯定&#xff0c;大家都在探索JDK 8的新功能。但是&#xff0c;在您完全研究Java 8之前&#xff0c;是时候重新审视Java 7上引入的一些很棒的功能了。记住&#xff0c;Java 6并没有什么功能&#xff0c;它只与JVM的更改和性能有关&…

java版本号管理_微服务项目中如何管理依赖版本号?

本文是微服务项目代码组织形式三部曲中的第三篇&#xff0c;也是最后一篇&#xff0c;通过这三篇文章&#xff0c;相信大家对于如果组织微服务中的代码已经有了一个基本认知&#xff0c;前面两篇分别是&#xff1a;第三篇相对来说要简单一些&#xff0c;本来没打算写&#xff0…

React之函数中的this指向

我们都知道在React中使用函数时&#xff0c;有两种写法&#xff0c;一是回调函数&#xff0c;二是直接调用&#xff0c;但需要在构造函数中绑定this&#xff0c;只有这样&#xff0c;函数中的this才指向本组件 总结一下没有绑定this的函数中的this指向 不管是在本组件的元素上调…

对于刚开始使用该软件,应该在熟悉基本的markdown语法的基础上,再进行快捷键的使用!...

一级标题 # 空格 编写内容 二级标题 ## 空格 编写内容 有序内容 1.Tab 无序内容 -Tab 代码块 print("hello wrold") typora快捷键 ctrl1一级标题 添加图片 表格 CtrlT 姓名年龄职业谢国宏20IT文字加粗 24期的小伙伴们你们好 文字斜体 你好 又粗又斜 粗斜* 3**2 -- 幂…

struct和byte[]相互转换(用Marshal类实现)

转自[DotNet笔记]相当于序列化与反序列化&#xff0c;但是不用借助外部文件1、struct转换为byte[] 1staticbyte[] StructToBytes(objectstructObj) 2{ 3 int size Marshal.SizeOf(structObj); 4 IntPtr buffer Marshal.AllocHGlobal(size); 5 …

Get-CrmSetting返回Unable to connect to the remote server的解决办法

摘要: 微软动态CRM专家罗勇 &#xff0c;回复302或者20190125可方便获取本文&#xff0c;同时可以在第一间得到我发布的最新博文信息&#xff0c;follow me&#xff01;我的网站是 www.luoyong.me 。 在Dynamics 365部署管理器所在的服务器上执行Get-CrmSetting&#xff0c;最近…

使用ReentrantLock和Lambdas进行干净同步

最近&#xff0c;我在阅读一篇内容丰富的文章&#xff0c;内容涉及Javin Paul 1 synchronized和ReentrantLock之间的区别。 他强调了后者的优点&#xff0c;但并未保留一些缺点&#xff0c;这些缺点与正确使用所需的繁琐的try-finally块有关。 在同意他的陈述的同时&#xff0…

java 二维数组奇数金字塔_二维数组:奇数阶魔方 | 新思维:C语言程序设计

幻方&#xff0c;有时又称魔方&#xff0c;由一组排放在正方形中的整数组成&#xff0c;其每行、每列以及两条对角线上的数之和均相等。通常幻方由从到的连续整数组成。Siamese方法(Kraitchik 1942年&#xff0c;pp. 148-149)是构造奇数阶幻方的一种方法&#xff0c;说明如下&a…

react-性能优化

开发中遇到一个需要优化的性能&#xff0c;页面需要渲染很多table&#xff0c;而且可以自己添加table&#xff0c;所以就导致router改变时&#xff0c;清除这些DOM结构就会很慢&#xff0c;这就给用户造成不好的体验。 问题所在&#xff1a;清除渲染过多的DOM结构才导致迟缓&a…

Node.js学习(篇章一)

<node.js的特点> 采用了异步式I/O与事件驱动的架构设计&#xff0c;架构为单线程模型。 <supervisor包的作用> node.js开发项目&#xff0c;当修改项目时&#xff0c;需要终止进程重启Node.js之后才可以看到修改后的效果&#xff0c;为了解决这个问题&#xff0c;我…

WinXP启动时自动打开上次关机时未关闭的文件夹

不能自动打开上次关机时未关闭的文件夹解决方法&#xff1a; 首先运行注册表&#xff0c;解决方法&#xff1a;打开[\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] 在右面的窗口中新建DWORD类型键值“PersistBrowsers”&#xff0c;数据为…

机器学习前沿02

自动机器学习 https://mbd.baidu.com/newspage/data/landingsuper?context%7B%22nid%22%3A%22news_9244479631915180647%22%7D&n_type1&p_from3 卷积网络的综述 https://mbd.baidu.com/newspage/data/landingsuper?context%7B%22nid%22%3A%22news_979691604239366144…

java 判断闰年和月份_java----根据输入的年月判断闰年和打印日历

import java.util.Scanner;import java.text.ParseException;import java.util.Calendar;public class Calendar {public static void main(String[] args) throws ParseException {Scanner sc new Scanner(System.in);System.out.println("请输入年份&#xff1a;"…