http://www.itint5.com/oj/#22

这题一开始直接用暴力的DFS来做,果然到25的规模就挂了.

vector<bool> visited(50, false);
vector<vector<int> > vec_row(50);
vector<vector<int> > vec_col(50); bool findPath(vector<int> &x, vector<int> &y, int idx, int depth, int direction) {
if (depth == x.size()) return true;
visited[idx] = true;
if (direction == 0) {
int row = x[idx];
for (int i = 0; i < vec_row[row].size(); i++) {
if (!visited[vec_row[row][i]]) {
if (findPath(x, y, vec_row[row][i], depth+1, 1))
return true;
}
}
} else {
int col = y[idx];
for (int i = 0; i < vec_col[col].size(); i++) {
if (!visited[vec_col[col][i]]) {
if (findPath(x, y, vec_col[col][i], depth+1, 0))
return true;
}
}
} visited[idx] = false;
return false;
} //如果存在满足条件的遍历,返回true,否则返回false
bool existPath(vector<int> &x, vector<int> &y) {
int k = x.size();
if (k == 0) return true;
for (int i = 0; i < k; i++) {
vec_row[x[i]].push_back(i);
vec_col[y[i]].push_back(i);
}
for (int i = 0; i < k; i++) {
if (findPath(x, y, i, 1, 0) ||
findPath(x, y, i, 1, 1)) {
return true;
}
}
return false;
}

正确的做法是转化成欧拉回路:http://www.itint5.com/discuss/22/%E7%9B%B4%E8%A7%92%E8%B7%AF%E7%BA%BF%E9%81%8D%E5%8E%86%E6%A3%8B%E7%9B%98

这题可以直接转换为欧拉回路(路径)问题,这样,如果有解的时候要输出遍历路径的时候,也比较好办了。
具体的转换方式为:n,m的棋盘,建一个包含n+m个顶点的图G(为了方便说明,类似二分图将其分为两列,左边n个顶点,右边m个顶点,分别代表n行和n列)。对于目标格子(i,j),左边第i个顶点和右边第j个顶点连一条边。最后的问题其实就是问转换之后的图G是否存在欧拉欧拉回路或者欧拉路径。
证明:相邻两步为直角,其实就是从某一行变到某一列。访问图G中的一条边,意味着访问棋盘中的一个目标点。由于图G中的边只连接左边的点(代表某一行)和右边的点(代表某一列),因此访问一条边就意味着从某一行变到了某一列,也就是转直角了。
所以问题变为能否从一点出发访问G中的所有边有且仅有一次。这个就是欧拉回路问题了。

所以欧拉路径是:1.连通;2.奇点为2,为0时是欧拉回路。

这里的连通我用并查集来做。注意写并查集的merge时,要先找到根,再merge。

vector<int> djset;

int find(int i) {
int x = i;
while (djset[x] != x) {
x = djset[x];
}
djset[i] = x;
return x;
} void merge(int i, int j) {
djset[find(i)] = djset[find(j)];
} //如果存在满足条件的遍历,返回true,否则返回false
bool existPath(vector<int> &x, vector<int> &y) {
vector<int> axis(100, 0);
// 计算奇点数目
for (int i = 0; i < x.size(); i++) {
axis[x[i]] = !axis[x[i]]; // 奇偶变换
}
for (int i = 0; i < y.size(); i++) {
axis[y[i]+50] = !axis[y[i]+50];
}
int count = 0;
for (int i = 0; i < axis.size(); i++) {
if (axis[i]) count++;
}
if (count != 0 && count != 2) return false; djset.resize(x.size());
for (int i = 0; i < djset.size(); i++) {
djset[i] = i;
} // 判断连通性
for (int i = 0; i < x.size(); i++) {
for (int j = i+1; j < x.size(); j++) {
if (x[i] == x[j]) {
merge(i, j);
}
}
}
for (int i = 0; i < y.size(); i++) {
for (int j = i+1; j < y.size(); j++) {
if (y[i] == y[j]) {
merge(i, j);
}
}
} for (int i = 0; i < x.size(); i++) {
if (find(i) != find(0)) {
return false;
}
}
return true;
}

  

[itint5]直角路线遍历棋盘的更多相关文章

  1. POJ_2488——骑士遍历棋盘,字典序走法

    Description Background The knight is getting bored of seeing the same black and white squares again ...

  2. day53-马踏棋盘

    马踏棋盘 1.算法优化的意义 算法是程序的灵魂,为什么有些程序可以在海量数据计算时,依旧保持高速计算? 编程中算法很多,比如八大排序算法(冒泡.选择.插入.快排.归并.希尔.基数.堆排序).查找算法. ...

  3. visual_c++外挂教程(详细)

    课程分四个大章节 初级篇,中级篇,进阶篇,高级篇 初级篇内容:编写一个完整的,简单的外挂 C++的数据类型:Byte,Word,DWORD,int,float API函数的调mouse_event,G ...

  4. NOI 题库 8465

    8465  马走日 描述 马在中国象棋以日字形规则移动. 请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点. ...

  5. chineseChess

    最近学习了chineseChess的Qt实现,把一些东西总结一下: 实现功能: 1.人人对战 2.人机对战 3.网络版 一.基础性工作:(人人对战) 1.棋盘和棋子的绘制(QPinter,drawLi ...

  6. noi 8465 马走日

    8465:马走日 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  1024kB 描述 马在中国象棋以日字形规则移动. 请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y ...

  7. poj 3279 Fliptile

    题意:一个n * m的棋盘,0或1,每次改变一个格子时同时改变上下左右的格子,问用最少次数将棋盘全变成0的策略. 题解:用二进制压缩第一行更改的状态,之后遍历棋盘,如果当前格子为1则改变下方的格子,记 ...

  8. 听说alphago又要挑战sc2了?——我眼中的人工智能

    乱谈: 之前alphago进行的围棋比赛相当火爆. 一时间我的朋友圈都爆了,因为同学以及相关专业的同学都在发这个,毕竟逼格一下就起来了,我也大肆转发.各种角度,不同层次的不同深度的文章也都扫了几眼. ...

  9. web版扫雷小游戏(二)

    接上篇~~第一次写这种技术博客,发现把自己做的东西介绍出来还是一件脑力活,不是那么轻松啊,好吧,想到哪写到哪,流水记录之,待完成之后再根据大家的意见进行修改吧. 游戏实现 根据对扫雷游戏的体验和分析, ...

随机推荐

  1. Quartz.NET快速上手第一课(官网文档翻译)

    Quartz.NET快速上手第一课(官网文档翻译) 原文链接 在你使用调度者(scheduler)之前,你需要对它进行实例化(谁能猜到这呢?).在实例化scheduler时候,你需要使用ISchedu ...

  2. BT之下拉菜单

    <div class="dropdown"> <button class="btn btn-default dropdown-toggle" ...

  3. 如何找到Linux下常用命令的源码

    Linux系统,常用命令的来源很多,有些命令是shell自带的,比如cd,通过执行help命令,可以查看当前系统所有的内置命令. 用type <cmd_name>来查看一个命令是否为内置命 ...

  4. 一个封装好的C++比特数组BitArray,可以对位进行直接操作

    本来仅仅只是用来做哈夫曼实验时的辅助,后来一想干脆封装好,省得以后又要用到比特位的操作. 基本用法示例:  BitArray bits; bits[] = ; bits[] = ; cout<& ...

  5. Java中的分代垃圾回收策略

    一.分代GC的理论基础 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大 ...

  6. String inputStream file转化

    String --> InputStreamByteArrayInputStream stream = new ByteArrayInputStream(str.getBytes()); Inp ...

  7. [DevExpress][TreeList]条件隐藏节点CheckBox

    关键代码: /// <summary> /// 隐藏CheckBox /// 说明 /// 在CustomDrawNodeCheckBox事件中使用 /// eg: /// TreeLis ...

  8. ListView 复制到剪切板

    private void 导出ToolStripMenuItem_Click(object sender, EventArgs e) { Clipboard.SetText(GetListView(l ...

  9. encodeURIComponent与encodeURI的区别

    encodeURIComponent()   -->把字符串编码为 URI 组件. encodeURI()                   -->把字符串编码为 URI. var te ...

  10. Canvas开发笔记(不断更新)

    1.可以使用requestAnimationFrame函数代替setInterval.需要处理浏览器兼容问题: var w = window; requestAnimationFrame = w.re ...