写在前面

UVA的题需要自己读入一个 \(T\) 组数据,别被样例给迷惑了

Solution

每个格子只有两种填法且 \(n \le 7\),暴力搜索两种填法,开cnt数组统计连接个数。

填一个格子,如果是 "\",格子左上角和右下角的 \(cnt++\),如果是 "/",格子左下角和右上角的 \(cnt++\)。只有更改后的 \(cnt\) 小于等于目标 \(cnt\)才继续向下搜,否则回溯

发现每填一个格子,连接格子左上角的格点的个数就可以被确定,那么只有左上角的格点个数等于目标格点个数或没有要求才继续搜索,否则回溯

如果搜索到第 \(n + 1\) 列时,要额外判断边界第 \(n + 1\) 列的 \(cnt\)是否满足对应的个数

如果搜索到第 \(n\) 行时,要额外判断边界第 \(n + 1\) 行的 \(cnt\) 是否满足对应个数

如何保证无环?不难想到,只有在填 "/" 时才有可能出现环,那么在填 "/" 之前,先判断是否有环

如何处理点的坐标?把行看做十位,把列看做个位就好啦

  • 算法一:考虑可撤销并查集,然而我不会

  • 算法二:发现n很小,每次判断时 \(n^2\) 扫一遍建图,在 \(dfs\) 看看能否从左下角跑到右上角

  • 算法三:很显然算法二很傻逼,直接用并查集维护就好,加完边后判断左下角和右上角是否在同一并查集里,省去 \(dfs\) 的时间,注意清零!

最后输出方案就好啦

Code

我一开始建图跑的,后来也没改(因为懒

  1. /*
  2. Work by: Suzt_ilymics
  3. Knowledge: ??
  4. Time: O(??)
  5. */
  6. #include<iostream>
  7. #include<cstdio>
  8. #include<cstring>
  9. #include<algorithm>
  10. #define LL long long
  11. #define orz cout<<"lkp AK IOI!"<<endl
  12. using namespace std;
  13. const int MAXN = 10;
  14. const int INF = 1;
  15. const int mod = 1;
  16. struct edge{
  17. int from, to, nxt;
  18. }e[10100 << 1];
  19. int head[MAXN * MAXN], num_edge = 0;
  20. int n;
  21. int go[MAXN][MAXN];
  22. int cnt[MAXN][MAXN], now[MAXN][MAXN];
  23. bool flag = false, Flag = false;
  24. int read(){
  25. int s = 0, f = 0;
  26. char ch = getchar();
  27. while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
  28. while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
  29. return f ? -s : s;
  30. }
  31. void add_edge(int from, int to){
  32. e[++num_edge] = (edge){from, to, head[from]}, head[from] = num_edge;
  33. }
  34. bool bl(int u, int fa, int end){
  35. for(int i = head[u]; i != -1; i = e[i].nxt){
  36. int v = e[i].to;
  37. if(v == fa) continue;
  38. if(v == end) {
  39. Flag = 1;
  40. return true;
  41. }
  42. bl(v, u, end);
  43. if(Flag) { return true; }
  44. }
  45. return false;
  46. }
  47. bool pd(int sx, int sy, int ex, int ey){
  48. memset(head, -1, sizeof(head)); num_edge = 0;
  49. Flag = false;
  50. for(int i = 1; i <= n; ++i){
  51. for(int j = 1; j <= n; ++j){
  52. if(now[i][j] == 0){
  53. add_edge(i * 10 + j, (i + 1) * 10 + j + 1);
  54. add_edge((i + 1) * 10 + j + 1, i * 10 + j);
  55. }
  56. if(now[i][j] == 1){
  57. add_edge((i + 1) * 10 + j, i * 10 + j + 1);
  58. add_edge(i * 10 + j + 1, (i + 1) * 10 + j);
  59. }
  60. }
  61. }
  62. if(bl(sx * 10 + sy, 0, ex * 10 + ey)) return 1;
  63. else return 0;
  64. }
  65. void dfs(int posx, int posy){
  66. // cout<<posx<<" "<<posy;
  67. // orz;
  68. if(posx == n && posy == n + 1) {
  69. if( ((cnt[posx + 1][posy] == go[posx + 1][posy]) || (go[posx + 1][posy] == 9)) && ((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9)) ) flag = 1;
  70. return ;
  71. }// 如果搜到最后一个点,说明已经找到答案。退出
  72. if(posy == n + 1){ //如果这一行搜完了
  73. if((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9) ) posx++, posy = 1;//换行
  74. else return ;// 如果已经确定的那个数并没有达到目标,返回
  75. }//
  76. now[posx][posy] = 0;// 填 "\"
  77. cnt[posx][posy]++, cnt[posx + 1][posy + 1]++;// 对应位置加1
  78. if(cnt[posx][posy] <= go[posx][posy] && cnt[posx + 1][posy + 1] <= go[posx + 1][posy + 1]) {//如果两个对应位置大于目标位置就不向下搜索
  79. if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//如果已经确定的那个数没有达到目标,停止向下搜索
  80. if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){
  81. dfs(posx, posy + 1);//
  82. }
  83. }
  84. }//
  85. if(flag) return ;// 如果找到答案就返回
  86. cnt[posx][posy]--, cnt[posx + 1][posy + 1]--;//回溯
  87. if(pd(posx + 1, posy, posx, posy + 1)){ return ;}
  88. now[posx][posy] = 1;// 填 "/"
  89. cnt[posx + 1][posy]++, cnt[posx][posy + 1]++;// 对应位置加1
  90. if(cnt[posx + 1][posy] <= go[posx + 1][posy] && cnt[posx][posy + 1] <= go[posx][posy + 1]) {//如果两个对应位置大于目标位置就不向下搜索
  91. if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//如果已经确定的那个数没有达到目标,停止向下搜索
  92. if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){
  93. dfs(posx, posy + 1);//
  94. }
  95. }
  96. }
  97. if(flag) return ;// 如果找到答案就返回
  98. now[posx][posy] = -1;//回溯
  99. cnt[posx + 1][posy]--, cnt[posx][posy + 1]--;// 回溯
  100. }
  101. int main()
  102. {
  103. // freopen("gokigen.in","r",stdin);
  104. // freopen("gokigen.out","w",stdout);
  105. int T;
  106. T = read();
  107. while(T--){
  108. n = read();
  109. memset(now, -1, sizeof(now));
  110. memset(cnt, 0, sizeof(cnt));
  111. memset(go, 0, sizeof(go));
  112. flag = 0;
  113. char ch[10];
  114. for(int i = 1; i <= n + 1; ++i){
  115. cin>>(ch + 1);
  116. for(int j = 1; j <= n + 1; ++j){
  117. if(isdigit(ch[j])) go[i][j] = ch[j] - '0';
  118. else go[i][j] = 9;
  119. }
  120. }
  121. dfs(1, 1);
  122. // for(int i = 1; i <= n + 1; ++i){
  123. // for(int j = 1; j <= n + 1; ++j){
  124. // cout<<go[i][j]<<" ";
  125. // }
  126. // cout<<"\n";
  127. // }
  128. // cout<<"\n";
  129. //
  130. // for(int i = 1; i <= n + 1; ++i){
  131. // for(int j = 1; j <= n + 1; ++j){
  132. // cout<<cnt[i][j]<<" ";
  133. // }
  134. // cout<<"\n";
  135. // }
  136. // cout<<"\n";
  137. for(int i = 1; i <= n; ++i){
  138. for(int j = 1; j <= n; ++j){
  139. if(now[i][j] == 1) cout<<"/";
  140. else if(now[i][j] == 0) cout<<"\\";
  141. else cout<<"s";
  142. }
  143. cout<<"\n";
  144. }
  145. }
  146. return 0;
  147. }

UVA11694 Gokigen Naname题解的更多相关文章

  1. 题解 UVA11694 【Gokigen Naname谜题 Gokigen Naname】

    题目 题解 考场上连暴力都不会打的码农题,深搜是真的难 /kk 前置问题 怎么输出"\" cout<<"\\"; 2.怎么处理不在一个环里,可以考虑 ...

  2. Uva 11694 Gokigen Naname

    基本思路是Dfs: 1. 一个一个格子摆放,以每个各自的左上角的点为基准点代表格子,比如(0,0)代表(0,0)(0,1)(1,0)(1,1)组成的格子,(0,1)代表(0,1)(0,2)(1,1), ...

  3. UVA11694-Gokigen Naname(DFS进阶)

    Problem UVA11694-Gokigen Naname Accept: 76   Submit: 586Time Limit: 10000 mSec Problem Description I ...

  4. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  5. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  6. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  7. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  8. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  9. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

随机推荐

  1. pathon基础2

    支持不同文件,不同sheet页 import xlrdimport xlwtimport osimport time; #往日志文件中追加内容函数def writeLogfile(filename,c ...

  2. eclipse 项目没错却有红叉(解决方法)

    eclipse如何去掉无用的validation.优化eclipse 注意:本经验使用的eclipse版本为 Eclipse Java EE IDE for Web Developers. Versi ...

  3. 在 ASP.NET Core和Worker Service中使用Quartz.Net

    现在有了一个官方包Quartz.Extensions.Hosting实现使用Quartz.Net运行后台任务,所以把Quartz.Net添加到ASP.NET Core或Worker Service要简 ...

  4. JavaScript 函数节流和函数去抖

    概念 函数防抖(debounce) 当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间 函数节流(throttle) 预先设定一个执行周期,当调用动作的时刻大于等于执 ...

  5. 别再费劲去找后台的前端框架了,2021 年就用 Fantastic-admin 吧

    前言 你知道光是基于 Vue 的后台框架在 Github 上有多少个仓库么? 如果你搜索 vue admin 会得到 13120 个仓库,如果用 vue 后台 会得到 7596 个仓库,如果把两者结合 ...

  6. Pytest测试框架(五):pytest + allure生成测试报告

    Allure 是一款轻量级.支持多语言的开源自动化测试报告生成框架,由Java语言开发,可以集成到 Jenkins. pytest 测试框架支持Allure 报告生成. pytest也可以生成juni ...

  7. i5 11300H和i5 10300H 的区别

    i5-11300H 为 4 核 8 线程,主频 3.1GHz,睿频 4.4GHz,三级缓存 8MB 选 i5-11300H还是i5 10300h 这些点很重要!看完你就知道了https://list. ...

  8. 使用Python实现的4种快速排序算法

    快速排序算法,总体来说就是选一个基准值,把小于基准值的分一拨,把大于基准值的分到另一拨,然后递归. 有区别的是,分区算法有差异,最直接的是,选个基准值,定义两个列表(小值分区less和大值分区grea ...

  9. 网络之HTTPS

    文章目录 HTTPS的基本概念 HTTP和HTTPS的区别 HTTPS的优点 对称加密和非对称加密 对称加密 非对称加密 HTTPS采用的加密方式 认证 证书的组成 使用openssl怎么制造证书 H ...

  10. canvas多重阴影发光效果

    canvas多重阴影发光效果 前言 在一个项目中,客户提了一个发光的效果,效果图如下: 阴影 有的人可能会说,这个用阴影其实就可以实现.但是从图中可以看出,是一个比较强烈的发光效果.实际的应用过程中我 ...