通过几道例题简单阐述一下DFS的相关题型


ZOJ2412-Farm Irrigation

  直观的DFS题型,稍加变化,记录好四个方向上的通路就能够做出来

  题目和接水管类似,问最少要灌溉几次,即求解最少有多少个连通子图。

  

 //和接水管游戏类似,将相应水管通路标记清晰即可
//Time:0Ms Memory:270K
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAX 55
#define OPPOSITE(x) ((x + 2) % 4) //x的相反位置
#define MAP(x,y) (map[x][y] - 'A') //水管序列
int row, col;
char map[MAX][MAX];
bool v[MAX][MAX];
int mov[][] = { {, }, {, }, {, -}, {-, } }; //东南西北
bool face[][] = { //face[i][j] : 在i方向上第j个水管是否有通路
{ ,,,,,,,,,, }, //东
{ ,,,,,,,,,, }, //南
{ ,,,,,,,,,, }, //西
{ ,,,,,,,,,, } //北
};
void dfs(int x,int y)
{
v[x][y] = true;
for (int i = ; i < ; i++)
{
int tx = x + mov[i][];
int ty = y + mov[i][];
if (face[i][MAP(x,y)] && tx >= && tx < row && ty >= && ty < col) //该水管相应对接方向有通路
{
if (!v[tx][ty] && face[OPPOSITE(i)][MAP(tx,ty)]) //对接水管相应方向有通路
dfs(tx, ty);
}
}
}
int main()
{
while (scanf("%d%d", &row, &col), row != - && col != -)
{
memset(v, false, sizeof(v));
for (int i = ; i < row; i++)
scanf("%s", map[i]);
int times = ;
for (int i = ; i < row; i++)
for (int j = ; j < col; j++)
{
if (!v[i][j]) {
times++;
dfs(i, j);
}
}
printf("%d\n", times);
}
return ;
}

ZOJ1008-Gnome Tetravex

  看起来不像个搜索题,初看可能会以为需要枚举之类的,但是题中方块的各状态需要记录,在匹配失败时需要回退,因此是一道DFS题型。

  大致的解题思路就是先枚举0行0列的方块,再依据此方块固定下一个方块,以此类推,出现不能匹配时回退。

  虽然规模最大只有5,但是总方块数25个在DFS中也不可小觑,如果用纯DFS来做,时间度最坏可以达到O((n^2)!),因此剪枝或其他优化是必须的(只要数据不够水),我在超时后看了很多博客的解题报告(想不到了= =),就该题数据而言最好的优化方法是去重,即将相同方块合在一起,以减少DFS的分支数,但是我总觉得这么做挺奇怪的。。。虽然在大数据下,此题去重很有效果(数字在0-9,因此方块重复概率 < 1/2500),但是此题拿小数据故意出多组重复方块,不得不让人怀疑其心不善...

  

  另外的剪枝方法,也有很多比较有效,但对此题没有太大帮助。

    例如:记录各方向上各数字的个数,在匹配时动态增删,如果已经固定的方块需要的对应数字的数量缺失,那么就可以直接回退,剪枝效果在少量随机数据情况下比较好。

    

 //去重就不会超时了,但这个优化实在是...让人感到很意外
//Time:2100ms Memory:272K
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std; #define MAX 28 int n, m;
int sq[MAX][]; //上右下左
int board[MAX]; //棋盘上对应位置的square
int v[MAX]; //记录同类sq未被使用的数量 bool dfs(int num)
{
if (num == n*n)
return true;
//找出可以充当第num个方块的i方块
for (int i = ; i < m; i++)
{
if (!v[i]) continue; //没有未固定方块
if (num % n && sq[i][] != sq[board[num - ]][]) continue; //非第一列+不匹配
if (num / n && sq[i][] != sq[board[num - n]][]) continue; //非第一行+不匹配 v[i]--;
board[num] = i;
if (dfs(num + )) return true;
else v[i] ++;
}
return false;
} int main()
{
int t = ;
while (scanf("%d", &n), n)
{
if (t) printf("\n"); memset(v, , sizeof(v));
memset(board, , sizeof(board));
m = ;
for (int i = ; i < n*n; i++)
{
int u, r, d, l;
scanf("%d%d%d%d", &u, &r, &d, &l);
//查重
bool flag = false;
for (int j = ; j < m; j++)
{
if (u == sq[j][] && r == sq[j][] && d == sq[j][] && l == sq[j][])
{
v[j]++;
flag = true;
break;
}
}
if (!flag) {
sq[m][] = u; sq[m][] = r; sq[m][] = d; sq[m][] = l;
v[m++] ++;
}
} if (dfs()) printf("Game %d: Possible\n", ++t);
else printf("Game %d: Impossible\n", ++t);
} return ;
}

ACM/ICPC 之 DFS范例(ZOJ2412-ZOJ1008)的更多相关文章

  1. ACM/ICPC 之 DFS+SPFA-贪心+最短路(POJ2679)

    //POJ2679 //DFS+SPFA+邻接表 //只能走每个点费用最小的边,相同则需保证距离最短 //求最小费用及最短距离 //Time:47Ms Memory:900K #include< ...

  2. ACM/ICPC 之 DFS求解欧拉通路路径(POJ2337)

    判断是欧拉通路后,DFS简单剪枝求解字典序最小的欧拉通路路径 //Time:16Ms Memory:228K #include<iostream> #include<cstring& ...

  3. ACM/ICPC 之 DFS求解欧拉回路+打表(POJ1392)

    本题可以通过全部n位二进制数作点,而后可按照某点A的末位数与某点B的首位数相等来建立A->B有向边,以此构图,改有向图则是一个有向欧拉回路,以下我利用DFS暴力求解该欧拉回路得到的字典序最小的路 ...

  4. ACM/ICPC 之 Floyd范例两道(POJ2570-POJ2263)

    两道以Floyd算法为解法的范例,第二题如果数据量较大,须采用其他解法 POJ2570-Fiber Network //经典的传递闭包问题,由于只有26个公司可以采用二进制存储 //Time:141M ...

  5. ACM/ICPC 之 Prim范例(ZOJ1586-POJ1789(ZOJ2158))

    两道Prim解法范例题型,简单的裸Prim,且两题相较以边为重心的Kruskal解法而言更适合以点为重心扩展的Prim解法. ZOJ1586-QS Network 题意:见Code 题解:直接的MST ...

  6. ACM/ICPC 之 Kruskal范例(ZOJ1203-POJ1861(ZOJ1542))

    两道最小生成树范例,Kruskal解法-以边为主体扩展最小生成树,需要利用并查集. ZOJ1203-Swordfish 题意:求n个给定平面坐标的城市中的一条平面距离上的最短路长(保留两位小数) 题解 ...

  7. ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)

    两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路. POJ3268-Silver Cow Party //计算正逆最短路径之和的最大值 //Time:32Ms Memory ...

  8. ACM/ICPC 之 BFS范例(ZOJ2913-ZOJ1136(POJ1465))

    通过几道经典BFS例题阐述BFS思路 ZOJ2913-Bus Pass 题意:找一个center区域,使得center到所有公交线路最短,有等距的center则输出id最小的. 题解:经典的BFS,由 ...

  9. hduoj 4707 Pet 2013 ACM/ICPC Asia Regional Online —— Warmup

    http://acm.hdu.edu.cn/showproblem.php?pid=4707 Pet Time Limit: 4000/2000 MS (Java/Others)    Memory ...

随机推荐

  1. 代码中access 的使用

     C++代码:if(access(strZip.c_str(), 0) == 0){...}    此处为判断strZip中文件是否存在   .c_str() 是他自身字符串名称,该名称是一个压缩文件 ...

  2. for while (list each)的用法

    each是返回数组 指针当前指向的 元素的 索引和值: 索引有四个值: 0, 1, key, value. 0和key是一样的, 1和value是一样的 但是each只是将数组指针 向前移动 一步, ...

  3. Linux服务器管理: 系统的进程管理ps命令

    源码包:2015-06-30 12:11:25 首先我们可以通过网络去下载相应的源码包:我们以apache为例: [root@localhostA1 opt]# wget http://archive ...

  4. vmstat、top

    vmstat是一个查看虚拟内存(Virtual Memory)使用状况的工具,使用vmstat命令可以得到关于进程.内存.内存分页.堵塞IO.traps及CPU活动的信息. vmstat 最常用的有两 ...

  5. 阿里云9折推荐码:0LGVW2

    阿里云9折推荐码:0LGVW2,第一次购买云服务器或云数据库可享受原价9折优惠.

  6. sqoop

    http://blog.csdn.net/yfkiss/article/details/8700480 http://www.cnblogs.com/admln/p/sqoop1-99-4-javaa ...

  7. git 初始化

    Git global setup git config --global user.name "杨清1" git config --global user.email " ...

  8. html 常用标签补充

    <body> <!--预处理标签 <pre>--> <pre> 你好, 空格 换3行. 你<sup>上标</sup>好<s ...

  9. 如何给wordpress外部链接自动添加nofollow

    wordpress多作者博客可以丰富网站的内容,但同时也会产生一些无关的链接,例如有些投机的人会考虑在文章中随意添加外部链接,如果你不想给这些外部链接传递权重,你需要给这些外部链接加上 rel=&qu ...

  10. js验证姓名和身份证号

    js验证真实姓名,是用的unicode字符的来进行匹配,而中国人的姓名长度一般都是2-4,所以重复匹配{2,4}次 1.js验证真实姓名 1 var regName =/^[\u4e00-\u9fa5 ...