【算法学习笔记】28.枚举法 解题报告 SJTU OJ 1255 1256 魔戒
1256. 你的魔戒?不,是你的魔戒。加强版
Description
在前往末日火山的途中,佛罗多与他的霍比特人同胞不幸被半兽人抓住了。半兽人要对每个霍比特人进行询问,以找出哪个霍比特人携带了至尊魔戒。每个霍比特人可能会说以下几种话:
I have the ring. 我有魔戒。
I have not the ring. 我没有魔戒。
XXX has the ring. XXX有魔戒。(XXX表示某个霍比特人的名字)
XXX has not the ring. XXX没有魔戒。
Today is XXX. 今天天气真好,是XXX吧!(XXX表示Monday/Tuesday/Wednesday/Thursday/Friday/Saturday/Sunday其中之一,只有首字母大写)
询问中所回答的其他话,都不列入考虑的范围之内。
半兽人所知道的是,霍比特人中有N个人始终说假话,而其他人始终说真话。
每个霍比特人可能会回答多句话也可能不会回答。
必有且仅有一个霍比特人携带了魔戒。(霍比特人中不一定有人叫佛罗多,且携带者不一定是佛罗多哦~)
现在,半兽人希望从中推断出谁是真正的魔戒持有者!
Input Format
输入由若干行组成,第一行有二个整数,M(1<=M<=10)、N(1<=N<=M)和P(1<=P<=20)。
M是半兽人抓到的霍比特人数,N是其中始终说谎的人数,P是得到的回答的总数。接下来M行,
每行是一个霍比特人的名字(英文字母组成,全部大写)。
往后有P行,每行开始是某个霍比特人的名宇,紧跟着一个冒号和一个空格,后面是一句回答,符合前表中所列格式。回答每行不会超过250个字符。
输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。
Output Format
如果你的程序能确定谁持有了魔戒,则输出他的名字。如果程序判断出不止一个人可能持有了魔戒,则输出 I am confused. 。如果程序判断出没有人可能持有魔戒,则输出 It is impossible! 。
Sample Input
3 1 5
FRODO
SAM
GOLLUM
FRODO: I have the ring.
FRODO: Today is Sunday.
GOLLUM: FRODO has the ring.
SAM: I have the ring.
SAM: How are you??
Sample Output
FRODO
Hint
对于60%的数据,将不涉及到日期。
使用getline(cin,变量名)来读入整行的字符串。
使用getchar()来读入可能有的多余的字符(如回车等等)。
使用字符串.substr(起始位置,长度)来截取字符串。
1255是输出每句非废话的数字代码 其实就是这道题的init部分 各种字符串处理..比较容易错的是由于没有对后半部分完全匹配,而是单纯地提取特征子串来判断,会导致出错。(比如 I has....等废话)
string weekdays[] = {"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}; int M,N,P; string names[10]; //是废话反悔人数+1 否则返回被指控的人的id int isRubbish(string str,int speakerID){ if(str==" I have the ring." || str==" I have not the ring.")return speakerID;for (int i=0; i<M; ++i) {string toCheck_1 = " "+names[i]+" has the ring.";//完全匹配string toCheck_2 = " "+names[i]+" has not the ring.";if(str==toCheck_1||str==toCheck_2)return i;}return M+1; }int main(int argc, char const *argv[]) {cin>>M>>N>>P;//各种字符串处理string statements[20];for (int i = 0; i < M;){string temp ;getline(cin,temp);if(temp!=""){names[i++] = temp;}}int flag1[20]={0},flag2[20]={0},flag3[20]={0};for (int i = 0; i < P; ++i){getline(cin, statements[i]);//flag1unsigned long loc = statements[i].find(":");int speakerid=0;if(loc!=-1){string nameCheck = statements[i].substr(0,loc);for (; speakerid<M; ++speakerid) if(names[speakerid]==nameCheck){flag1[i]=speakerid;break;}//flag2unsigned long frstB=0,scndB=0;frstB = statements[i].find(" ");//第一个空格位置scndB = statements[i].substr(frstB+1,statements[i].length()).find(" ");//第二个空格位置string f2 = statements[i].substr(frstB+1,scndB);//第一个单词 f2if(f2=="Today"){//说明是日期int weekdayId = 1;for (; weekdayId<=7; ++weekdayId) if(statements[i].find(weekdays[weekdayId-1])!=-1){flag2[i]=weekdayId;flag3[i]=3;break;}}else{//描述戒指 但是要注意 这个也有可能是含有名字和I的废话int receivedId = isRubbish(statements[i].substr(loc+1),speakerid);if(receivedId==M+1)//判断是不是废话continue;//是废话 终止此次循环 flag[3]保持0flag2[i]=receivedId;flag3[i]=(statements[i].find("not")==-1) ? 1 : 2;}}}//1255的输出部分// int rubbish=0;// for (int i = 0; i < P ; ++i) {// if(flag3[i]!=0){// cout<<flag1[i]<<" "<<flag2[i]<<" "<<flag3[i]<<endl;// }else// rubbish++;// }// if(rubbish==P)//全是废话// cout<<"Orz"<<endl;/**********1256的部分开始了*******///用枚举法(代入法)试试 ....= = 注意 星期几的正确性 也是在判断范围之内的int specious = 0,sid=0;//先计算一下只说废话和根本没说话的人..int rubbishPeople = 0;for (int i =0; i < M; ++i) {int yes = 1; int no_talk = 1;for (int j=0; j<P; ++j) if(flag1[j]==i) {//这个人说话了no_talk = 0;if(flag3[j]!=0)//这个人说的不是废话{ yes = 0;break; }}if(yes or no_talk) //只说废话 或者 根本没说话rubbishPeople++;}//枚举罪犯和日期 int checked[15] = {0};//0表示初始 1表示说了谎 2表示真话for (int i = 0; i < M; ++i){for (int j=1; j < 8; ++j){//假设i是带戒指的人 且今天是周jint people = 0;//people是说谎的人数int ok = 1;memset(checked, 0, sizeof(checked));for(int k=0 ;k<P; ++k ){if((flag3[k]==3 and flag2[k]!=j) or ((flag2[k]==i and flag3[k]==2) or (flag2[k]!=i and flag3[k]==1)))//说谎 {if(checked[flag1[k]]==2)//之前说过真话{ok=0;break;}checked[flag1[k]]=1;//之前没说过真话 }if((flag3[k]==3 and flag2[k]==j) or ((flag2[k]==i and flag3[k]==1) or (flag2[k]!=i and flag3[k]==2)))//说真话 {if(checked[flag1[k]]==1)//之前说了谎话{ok=0;break;}checked[flag1[k]]=2;}}if(!ok)//!ok表示有人在这种假设下 又说了真话又说了假话continue;//换一个日期for(int t = 0; t<M; t++){if(checked[t]==1)people++;//统计说谎的人数 } if(people<=N and people>=N-rubbishPeople)//此处认为rubbishPeople两种都有可能 {specious++;//嫌疑人++sid = i;if(specious>1){cout<<"I am confused."<<endl;return 0;}break;//换下一个人调查 此种环境下找到了一个嫌疑人就可以换嫌疑人了 }}}//1256的输出if(specious==1)cout<<names[sid]<<endl;else if(specious==0){cout<<"It is impossible!"<<endl;}return 0; }
1255+1256的双枚举
解决1256的第一种方法就是 枚举带戒指的人 和 日期 ,然后在当前的假设下,判断说谎人数是否可行。
第二种思路是这样的 就是先枚举带戒指的人,找到这种情况下,说真话的人的序列,认为这个序列的第一个说过和日期相关话的人说的话是真的,那么我们就得到了当前的日期,如果其他说真话的人说了其他的日期或者说谎话的人对日期说了真话 那么都认为这种假设(对于带戒指的人的假设)是错误的。
代码就不写了。。太累。。貌似可以优化一下。但是也优化不到那里去。因为在内层也要对所有的有关日期的话进行循环遍历。
转载于:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1256.html
【算法学习笔记】28.枚举法 解题报告 SJTU OJ 1255 1256 魔戒相关推荐
- 【算法学习笔记】67.状态压缩 DP SJTU OJ 1383 畅畅的牙签袋
思想来自:http://blog.pureisle.net/archives/475.html 主要思想是用1和0来表示是否被填,然后根据两行之间的状态关系来构建DP方程. 1.首先初始化第一行 计算 ...
- 【算法学习笔记】83.排序辅助 动态规划 SJTU OJ 1282 修路
此题倒是能用贪心骗点分... 其实对于每一个位置 , 我们知道最后的改善结果一定是原数列中的数 . (因为要尽量减少消耗, 可以考虑减小至和相邻的相同) 有了这个结论之后, 我们就考虑用dp来做这件事 ...
- 【算法学习笔记】73.数学规律题 SJTU OJ 1058 小M的机器人
Description 小M有很多个机器人,他们要么一直说真话,要么一直说假话. 然后每个人都说: (1). 不到N个人比我工作得多 (2). 至少M个人的工资比我高. 保证没有两个人的工作一样重,也 ...
- 网络流算法学习笔记——最大流问题基本概念和Ford-Fulkerson方法(标号法C++实现)
屈婉玲<算法设计与分析>第2版第7章网络流算法学习笔记. 基本概念 最大流问题,相当于有从s到t的供水系统,每段路径都有限定流量,除了s.t两地外,每个中间点都不能滞留,从s流入多少,就从 ...
- 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列
(为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...
- 【基础】基础算法学习笔记(状态空间)
基础算法学习笔记(状态空间) 一.状态空间 1.定义(什么是状态空间):一个实际问题的各种可能情况构成的集合.(解释:为什么需要算法来和程序来处理问题?如果一道题可以手算得到答案,换句话说就是存在通过 ...
- 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例
** 机器学习knn算法学习笔记使用sklearn库 ,莺尾花实例. 具体knn算法是怎样的我这里就不再详细论述.在这里我注意总结我使用knn算法进行一个分类的分析 ** 分析过程 1.前期准备 引入 ...
- Python最优化算法学习笔记(Gurobi)
微信公众号:数学建模与人工智能 github地址:https://github.com/QInzhengk/Math-Model-and-Machine-Learning Python最优化算法学习笔 ...
- 数学建模算法学习笔记
数学建模算法学习笔记 作为建模Man学习数学建模时做的笔记 参考文献: <数学建模姜启源第四版> 网上搜罗来的各种资料,侵删 1.线性预测 levinson durbin算法,自相关什么的 ...
最新文章
- 汇编的8种寻址方式,以及2个默认段寄存器
- 问题 | CSDN编辑图像怎么使图像居中、偏左、偏右
- 互联网1分钟 | 0327 华为P30系列发布;微信公号直播工具大范围开放内测资格
- 电脑没有ps怎么改照片dpi_PS入门笔记!新手必备
- 斜齿轮受力计算:理论计算virtual.lab motion 仿真
- MySQL安装叫重启,如何重启MySQL,正确启动MySQL
- 127.0.0.1 myz.php,附录 – 1.0升级到2.0注意事项 - GatewayWorker 2.x 3.x 手册
- 一道简单的题学到的东西
- 【Django 2021年最新版教程25】模板语言 前端for循环怎么用 实例
- 恶意软件可以使用风扇噪音盗取数据
- JavaScript 动态生成表格
- eXosip事件总结
- 【项目】“头脑王者”答题辅助软件
- python forward函数_Python——函数
- Unity 四种截图方法(相机视图、无UI、有UI、Game窗口)
- Ubuntu18.04 安装搭建 hadoop-3.3.0 集群
- 计算机认知训练效果,维持认知健康人群晚年认知功能的计算机认知训练
- 宝塔面板IP域名绑定
- 新手在IDEA如何创建一个Web项目
- python运动学仿真的意义_运动学仿真和动力学仿真有什么区别和联系?