当前位置:   article > 正文

HNU-离散数学-程序设计实验-消解法推理系统_c++消解法

c++消解法

 离散数学程序设计实验(占期末比重1.5%)

利用程序进行自然推理

希望能帮到HNUers,加油!

注释部分是原代码部分,如果帮到你了麻烦点个赞

  1. /*
  2. * 实验四
  3. * 利用消解法进行推理
  4. * by Arcticwolf
  5. * CSEE----Computer Science and Technology 21XX
  6. * 信息科学与工程学院----计算机科学与技术 21XX班----wolf
  7. * 学号202108XXXXXX
  8. */
  9. #include <string.h>
  10. #include <iostream>
  11. #include <cstdio>
  12. #include <cmath>
  13. #include <cstdlib>
  14. #include <algorithm>
  15. //修改点:可用#include<bits/stdc++.h>减少头文件数量
  16. struct tmd
  17. {
  18. char gs[120], gsLast[120], niyou[120];//前件与后件及理由
  19. int nLitter, nUsed, isLitter, isCond;
  20. };
  21. void nonoop2( char aa[] )
  22. {
  23. //!!p=p
  24. int i = 0, j = 0;
  25. while (i < strlen( aa ) - 2)
  26. {
  27. //至少还有两个字符
  28. if (((i + 1) < strlen( aa )) && (aa[i] == '!') && (aa[i + 1] == '!'))
  29. {
  30. j = i;
  31. while (j < strlen( aa ) - 2)
  32. {
  33. aa[j] = aa[j + 2];
  34. j++;
  35. }
  36. aa[j] = '\0';
  37. break;
  38. }
  39. else
  40. i++;
  41. }
  42. }
  43. void printYsh( struct tmd tmdrec[], int np )
  44. {
  45. int i = 0;
  46. for (i = 0; i < np; i++)
  47. {
  48. if (tmdrec[i].isLitter == 1)
  49. printf( "(%d)\t%s为真\t\t\t%s---文字\n", i + 1, tmdrec[i].gs, tmdrec[i].niyou );
  50. else if (tmdrec[i].isCond == 1)
  51. printf( "(%d)\t%s+%s为真\t\t\t%s---析取式\n", i + 1, tmdrec[i].gs, tmdrec[i].gsLast, tmdrec[i].niyou );
  52. else
  53. printf( "(%d)\t%s为真\t\t\t%s\n", i + 1, tmdrec[i].gs, tmdrec[i].niyou );
  54. }
  55. }
  56. /* 修改点1:调换函数位置,否则会出现调用未定义函数的情况 */
  57. int setNiyou( struct tmd tmdrec[], int np, char ny0[], int j0, int j1, int nUsed0, int isCond0, int isLitter0 )
  58. {
  59. //将字符串ny0与j0赋到推理意见中
  60. char stmdpj0[20], stmdpj1[20];
  61. int nLen1 = 0, j = 0, nLenj0 = 0, nLenj1 = 0;
  62. nLen1 = strlen( ny0 );
  63. itoa( j0 + 1, stmdpj0, 10 );
  64. nLenj0 = strlen( stmdpj0 );//前一个依据
  65. itoa( j1 + 1, stmdpj1, 10 );
  66. nLenj1 = strlen( stmdpj1 );//后一个依据
  67. if (j0 == -1)
  68. {
  69. //原始前提
  70. for (j = 0; j < nLen1; j++)
  71. tmdrec[np].niyou[j] = ny0[j];
  72. tmdrec[np].niyou[j] = '\0';
  73. }
  74. else if (j1 == -1)//由前一步推理所得结论
  75. {
  76. tmdrec[np].niyou[0] = '(';
  77. for (j = 0; j < nLenj0; j++)
  78. tmdrec[np].niyou[j + 1] = stmdpj0[j];
  79. tmdrec[np].niyou[j + 1] = ')';
  80. for (j = 0; j < nLen1; j++)
  81. tmdrec[np].niyou[j + 2 + nLenj0] = ny0[j];
  82. tmdrec[np].niyou[j + 2 + nLenj0] = '\0';
  83. }
  84. else
  85. {
  86. //由前二步推理所得
  87. tmdrec[np].niyou[0] = '(';
  88. for (j = 0; j < nLenj0; j++)
  89. tmdrec[np].niyou[j + 1] = stmdpj0[j];
  90. tmdrec[np].niyou[j + 1] = ')';
  91. tmdrec[np].niyou[nLenj0 + 2] = '(';
  92. for (j = 0; j < nLenj1; j++)
  93. tmdrec[np].niyou[nLenj0 + 3 + j] = stmdpj1[j];
  94. tmdrec[np].niyou[nLenj0 + 3 + j] = ')';
  95. for (j = 0; j < nLen1; j++)
  96. tmdrec[np].niyou[nLenj0 + nLenj1 + 4 + j] = ny0[j];
  97. tmdrec[np].niyou[nLenj0 + nLenj1 + 4 + j] = '\0';
  98. }
  99. tmdrec[np].nUsed = nUsed0;//附加前提从未使用过nUsed0,int isCond0,int isLitter0
  100. tmdrec[np].isCond = isCond0;//是条件式
  101. tmdrec[np].isLitter = isLitter0;//是文字
  102. }
  103. void swaptmd(tmd &a,tmd &b)
  104. {
  105. tmd temp;
  106. temp=a;
  107. a=b;
  108. b=temp;
  109. }
  110. int inputPrimary( struct tmd gs0[] )
  111. {
  112. struct tmd tmdp;
  113. char pstate[120];
  114. char *ny0 = "前提条件";
  115. char *ny1 = "条件式转为析取式";
  116. char *ny2 = "双条件导出的析取式";
  117. int i = 0, j = 0, nLen = 0, k = 0;
  118. int i0 = 0;//原始条件
  119. printf( "输完一个前提条件请按回车,不输直接回车则结束\n析+,合*,条-,双=,否定!\n前提中只能为双条件、单条件、析取式,\n若为2个条件的合取,请输入2个前提,文字请在最前面输入:\n" );
  120. while (1)
  121. {
  122. gets( pstate );
  123. nLen = strlen( pstate );
  124. if (nLen == 0)
  125. {
  126. break;
  127. }//设置nUsed,isLitter,isCond,nLittle的值
  128. //判断是否为文字
  129. if (nLen == 1)//标注单个文字
  130. {
  131. gs0[i].nLitter = strlen( pstate );
  132. gs0[i].gs[0] = pstate[0];
  133. gs0[i].gs[1] = '\0';
  134. gs0[i].gsLast[0] = '\0';
  135. setNiyou( gs0, i, ny0, -1, -1, 0, 0, 1 );//前提类型,无,无,未使用,不是条件式,是文字
  136. }
  137. else if ((nLen == 2) && (pstate[0] == '!')) //标注!p
  138. {
  139. gs0[i].nLitter = strlen( pstate );
  140. gs0[i].gs[0] = pstate[0];
  141. gs0[i].gs[1] = pstate[1];
  142. gs0[i].gs[2] = '\0';
  143. gs0[i].gsLast[0] = '\0';
  144. setNiyou( gs0, i, ny0, -1, -1, 0, 0, 1 );//前提类型,无,无,未使用,不是条件式,是文字
  145. }
  146. else
  147. {
  148. for (j = 0; j < nLen; j++)
  149. {
  150. if (pstate[j] == '-')//标注条件式p-q
  151. {
  152. gs0[i].nLitter = strlen( pstate );
  153. for (k = 0; k < nLen; k++)
  154. gs0[i].gs[k] = pstate[k];//整个表达式进入gs
  155. gs0[i].gs[k] = '\0';
  156. gs0[i].gsLast[0] = '\0';
  157. setNiyou( gs0, i, ny0, -1, -1, 0, 0, 0 );//前提类型,无,无,未使用,不是析取式,不是文字
  158. i++;
  159. gs0[i].nLitter = gs0[i - 1].nLitter;
  160. gs0[i].gs[0] = '!';
  161. for (k = 0; k < j; k++)
  162. gs0[i].gs[k + 1] = pstate[k];
  163. gs0[i].gs[k + 1] = '\0';
  164. nonoop2( gs0[i].gs );
  165. for (k = j + 1; k < nLen; k++)
  166. gs0[i].gsLast[k - j - 1] = pstate[k];
  167. gs0[i].gsLast[k - j - 1] = '\0';
  168. setNiyou( gs0, i, ny1, i - 1, -1, 0, 1, 0 );//前提类型,无,无,未使用,是条件式,不是文字
  169. break;
  170. }
  171. else if (pstate[j] == '=')//标注双条件p=q
  172. {
  173. //先保存双条件
  174. gs0[i].nLitter = strlen( pstate );
  175. for (k = 0; k < strlen( pstate ); k++) { gs0[i].gs[k] = pstate[k]; }//双条件全部进gs
  176. gs0[i].gs[k] = '\0';
  177. gs0[i].gsLast[0] = '\0';
  178. setNiyou( gs0, i, ny0, -1, -1, 0, 0, 0 );//前提类型,无,无,未使用,是条件式,不是文字
  179. //p-q即!p+q
  180. i++;
  181. gs0[i].nLitter = strlen( pstate );
  182. gs0[i].gs[0] = '!';
  183. for (k = 0; k < j; k++) { gs0[i].gs[k + 1] = pstate[k]; }//p进gs
  184. gs0[i].gs[k + 1] = '\0';
  185. for (k = j + 1; k < nLen; k++) { gs0[i].gsLast[k - j - 1] = pstate[k]; }//q进gsLast
  186. gs0[i].gsLast[k - j - 1] = '\0';
  187. setNiyou( gs0, i, ny2, i - 1, -1, 0, 1, 0 );//前提类型,无,无,未使用,是条件式,不是文字
  188. nonoop2( gs0[i].gs );//去掉可能存在的!!?
  189. //q-p=p+!q
  190. i++;
  191. gs0[i].nLitter = gs0[i - 1].nLitter;
  192. for (k = 0; k < j; k++) { gs0[i].gs[k] = pstate[k]; }//条件前件p进gs
  193. gs0[i].gs[k] = '\0';
  194. gs0[i].gsLast[0] = '!';
  195. for (k = j + 1; k < nLen; k++) { gs0[i].gsLast[k - j - 1 + 1] = pstate[k]; }//条件后件!q进gsLast
  196. gs0[i].gsLast[k - j - 1 + 1] = '\0';
  197. setNiyou( gs0, i, ny2, i - 2, -1, 0, 1, 0 );//前提类型,无,无,未使用,是条件式,不是文字
  198. nonoop2( gs0[i].gsLast );//去掉可能存在的!!?
  199. break;
  200. }
  201. else if (pstate[j] == '+')//标注析取式p+q,也要分解到gs与gsLast中
  202. {
  203. gs0[i].nLitter = strlen( pstate );
  204. for (k = 0; k < j; k++)
  205. gs0[i].gs[k] = pstate[k]; //前件进gs
  206. gs0[i].gs[k] = '\0';
  207. for (k = j + 1; k < nLen; k++)
  208. gs0[i].gsLast[k - j - 1] = pstate[k]; //条件全部进gs
  209. gs0[i].gsLast[k - j - 1] = '\0';
  210. setNiyou( gs0, i, ny0, -1, -1, 0, 1, 0 );//前提类型,无,无,未使用,是条件式,不是文字
  211. break;
  212. }
  213. }
  214. if (j >= nLen)//不是条件式,也不是文字,则是普通的条件
  215. {
  216. gs0[i].nLitter = strlen( pstate );
  217. for (k = 0; k < nLen; k++)
  218. gs0[i].gs[k] = pstate[k]; //公式全进gs
  219. gs0[i].gs[k] = '\0';
  220. gs0[i].gsLast[0] = '\0'; //gsLast为空串
  221. setNiyou( gs0, i, ny0, -1, -1, 0, 0, 0 );//前提类型,无,无,未使用,不是条件式,不是文字
  222. }
  223. }
  224. i++;//当前公式处理完以后,指针i的值增1
  225. }
  226. nLen = i;//按字符串的长度排序
  227. for (i = 0; i < nLen - 1; i++)
  228. {
  229. k = i;
  230. //for (j = i + 1; j < nLen - 1; j++)
  231. /* 修改点2:修改循环条件使得最后的元素可排序 */
  232. for (j = i + 1; j < nLen; j++)
  233. if (gs0[k].nLitter > gs0[j].nLitter)
  234. k = j;
  235. if (k > i)
  236. {
  237. /* 修改点3:使用自定义的swaptmd排序 */
  238. swaptmd(gs0[i],gs0[k]);
  239. // tmdp = gs0[i];
  240. // gs0[i] = gs0[k];
  241. // gs0[k] = tmdp;
  242. }
  243. }
  244. return nLen;
  245. }
  246. int main()
  247. {
  248. struct tmd gs0[100];//推理前提条件
  249. char result0[128]; //结论
  250. struct tmd tmdrec[1024];//最多1000步
  251. char stmdp[128];
  252. char lastNiYou[128] = " ";//上一个推理式的理由
  253. char *ny01 = "消解";
  254. int i = 0, j = 0, k = 0;
  255. int np = 1, np0 = 0, isOk = 0;
  256. int i0 = 0, nPosLitter = 0, nPosCond = 0;//文字起始的位置,首个文字的位置,消解式的位置
  257. np0 = inputPrimary( gs0 );
  258. //输入结论
  259. printf( "输入要推理的结论,结论只能是文字,\n若是条件式,析取式请先手工转换为条件,将前件作为附加前提:" );
  260. gets( result0 );
  261. fflush( stdin );
  262. for (i = 0; i < np0; i++)
  263. {
  264. tmdrec[i] = gs0[i];//所有原始公式转抄到tmdrec中
  265. }
  266. np = i;//推理队列的尾部指针
  267. nPosLitter = 0;//文字的位置号
  268. nPosCond = 0;//条件的位置号
  269. isOk = 0;
  270. i0 = -1;
  271. while (1)
  272. {
  273. i = i0 + 1;//寻找下一个文字,i是起始位置,np是命令串的长度
  274. while ((i < np) && (tmdrec[i].isLitter != 1))
  275. i++;
  276. if (i >= np)
  277. break;//找不到文字我就没法推理了
  278. i0 = i;//记录从源头查询的首个文字的位置号,下次从此号往后寻找
  279. nPosLitter = i;//记录文字的位置
  280. strcpy( stmdp, tmdrec[i].gs );//保存当前文字的内容
  281. np0 = np - 1;
  282. while (np > np0) //从当前文字的下一个位置起寻找析取式,则一路往下走
  283. {
  284. np0 = np;
  285. for (i = 0; i < np; i++)//找到一个没有用过的戏曲式
  286. if ((tmdrec[i].isCond == 1) && (tmdrec[i].nUsed == 0))
  287. break;
  288. if (i == np)
  289. break;//没有找到则结束推理,所有条件式都用到了
  290. while (i < np)//若找到了这样的条件式
  291. {
  292. if ((tmdrec[i].isCond == 1))//若是条件式
  293. {
  294. //与上条命令的来源不同,或者但是同为前提条件也是可以的,即首个字符不是(
  295. if (((strcmp( lastNiYou, tmdrec[i].niyou ) != 0) || ((strcmp( lastNiYou, tmdrec[i].niyou ) == 0) && tmdrec[i].niyou[0] != '(')))
  296. {
  297. if ((tmdrec[i].gs[0] == '!') && (stmdp[0] != '!') && (strlen( tmdrec[i].gs ) - strlen( stmdp ) == 1)) // !p+q p cuo
  298. {
  299. //如果析取式的前件与stmdp即可消解,则将后件保存的stmdp中
  300. j = 0;
  301. while (j < strlen( stmdp ))//依次比较每个字符
  302. {
  303. if (tmdrec[i].gs[j + 1] != stmdp[j])
  304. break;//有一个不相等则结束比较
  305. j++;
  306. }
  307. if (j >= strlen( stmdp )) //如果比到最后仍然相等,则这二个可消解
  308. {
  309. strcpy( lastNiYou, tmdrec[i].niyou );
  310. tmdrec[nPosLitter].nUsed++; //这个文字用过一次了
  311. tmdrec[i].nUsed++; //这个析取式用过一次了
  312. strcpy( stmdp, tmdrec[i].gsLast ); //将次消解结果保存到推导序列中
  313. strcpy( tmdrec[np].gs, stmdp ); //将当前推出来的结果保存起来
  314. tmdrec[np].gsLast[0] = '\0'; //后件清空,保存当前条件
  315. setNiyou( tmdrec, np, ny01, nPosLitter, i, 0, 0, 1 ); //前提类型,有,无,未使用,不是条件
  316. nPosLitter = np; //记录当前文字的序号
  317. np++;
  318. if (strcmp( result0, stmdp ) == 0)
  319. {
  320. isOk = 1; //推出结论同条原是调节的下一轮
  321. break;
  322. }
  323. }
  324. }
  325. else if ((tmdrec[i].gsLast[0] == '!') && (stmdp[0] != '!') && (strlen( tmdrec[i].gsLast ) - strlen( stmdp ) == 1)) //a+!b b dui
  326. {
  327. //如果析取式的后件与stmdp即可消解,则将前件保存到stmdp中
  328. j = 0;
  329. while (j < strlen( stmdp )) //依次比较每一个字符
  330. {
  331. if (tmdrec[i].gsLast[j + 1] != stmdp[j])
  332. break; //有一个不相等则结束比较
  333. j++;
  334. }
  335. if (j >= strlen( stmdp )) //如果比到最后仍然相等,则这两个可消解
  336. {
  337. strcpy( lastNiYou, tmdrec[i].niyou );
  338. tmdrec[nPosLitter].nUsed++; //这个文字用过一次了
  339. tmdrec[i].nUsed++; //这个析取式用过一次了
  340. strcpy( stmdp, tmdrec[i].gs ); //将次消解结果保存到推导序列中
  341. strcpy( tmdrec[np].gs, stmdp ); //将当前推出来的结果保存起来
  342. tmdrec[np].gsLast[0] = '\0'; //后件清空,保存当前条件
  343. setNiyou( tmdrec, np, ny01, nPosLitter, i, 0, 0, 1 ); //前提类型,有,无,未使用,不是条件
  344. nPosLitter = np; //记录当前文字的序号
  345. np++;
  346. if (strcmp( result0, stmdp ) == 0)
  347. {
  348. isOk = 1; //推出结论同条原是调节的下一轮
  349. break;
  350. }
  351. }
  352. }
  353. else if ((tmdrec[i].gs[0] != '!') && (stmdp[0] == '!') && (strlen( tmdrec[i].gs ) - strlen( stmdp ) == -1)) // p+q !p
  354. {
  355. //如果析取式的后件与stmdp即可消解,则将前件保存到stmdp中
  356. j = 0;
  357. while (j < strlen( tmdrec[i].gs )) //依次比较每一个字符
  358. {
  359. if (stmdp[j + 1] != tmdrec[i].gs[j])
  360. break; //有一个不相等则结束比较
  361. j++;
  362. }
  363. if (j >= strlen( tmdrec[i].gs ))
  364. {
  365. strcpy( lastNiYou, tmdrec[i].niyou );
  366. tmdrec[nPosLitter].nUsed++; //这个文字用过一次了
  367. tmdrec[i].nUsed++; //这个析取式用过一次了
  368. strcpy( stmdp, tmdrec[i].gsLast ); //将次消解结果保存到推导序列中
  369. strcpy( tmdrec[np].gs, stmdp ); //将当前推出来的结果保存起来
  370. tmdrec[np].gsLast[0] = '\0'; //后件清空,保存当前条件
  371. setNiyou( tmdrec, np, ny01, nPosLitter, i, 0, 0, 1 ); //前提类型,有,无,未使用,不是条件
  372. nPosLitter = np; //记录当前文字的序号
  373. np++;
  374. if (strcmp( result0, stmdp ) == 0)
  375. {
  376. isOk = 1; //推出结论同条原是调节的下一轮
  377. break;
  378. }
  379. }
  380. }
  381. else if ((tmdrec[i].gsLast[0] != '!') && (stmdp[0] == '!') && (strlen( tmdrec[i].gsLast ) - strlen( stmdp ) == -1)) //p+q !q
  382. {
  383. //如果析取式的后件与stmdp即可消解,则将前件保存到stmdp中
  384. j = 0;
  385. while (j < strlen( tmdrec[i].gsLast ))//依次比较每一个字符
  386. {
  387. if (stmdp[j + 1] != tmdrec[i].gsLast[j])
  388. break; //有一个不相等则结束比较
  389. j++;
  390. }
  391. if (j >= strlen( tmdrec[i].gsLast ))//如果比到最后仍然相等,则这两个可消解
  392. {
  393. strcpy( lastNiYou, tmdrec[i].niyou );
  394. tmdrec[nPosLitter].nUsed++; //这个文字用过一次了
  395. tmdrec[i].nUsed++; //这个条件用过一次了
  396. strcpy( stmdp, tmdrec[i].gs ); //将此中间结果保存到推导序列中
  397. strcpy( tmdrec[np].gs, stmdp ); //将当前推出来的结果保存起来
  398. tmdrec[np].gsLast[0] = '\0'; //后件清空,保存当前条件
  399. setNiyou( tmdrec, np, ny01, nPosLitter, i, 0, 0, 1 );//前提类型,有,无,未使用,不是条件式
  400. nPosLitter = np; //记录当前文字的序号
  401. np++;
  402. if (strcmp( result0, stmdp ) == 0)
  403. {
  404. isOk = 1; //推出结论同原始条件的下一轮
  405. break;
  406. }
  407. }
  408. }
  409. }
  410. }
  411. i++;//判断下一个表达式是否为条件,是否为可推理的条件式
  412. }
  413. }
  414. if (isOk == 1)
  415. break; //我推出来了,不要再找下一个文字了
  416. }
  417. if (isOk == 1)
  418. printf( "我推出来了,推理过程如下:\n" );
  419. else
  420. printf( "我推不出来,推理过程如下:\n" );
  421. printYsh( tmdrec, np );
  422. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/560981
推荐阅读
相关标签
  

闽ICP备14008679号