7.29 DFS总结
7.29 黄昏时刻
(一) 全排列
建模:
给了数字n 代表从1-n 个数全排列
思路:
1. 输入n,如果n值为‘0’,则退出程序
2. vis[i] 保存 是否对第i个数字进行访问
3. dfs 遍历1-n 个数字的全排列,若重复访问,则越过。直到最终访问结束输出访问的的结果。之后回溯删掉对数字的访问。
优化:
none
代码:
#include <stdio.h>
#include <string.h> int a[] ,n, vis[]; void dfs(int s) {
int i;
//如果dfs 次数为n,则输出a数组的内容
if(s == n) {
for(i = ; i < n; i++)
printf("%-5d", a[i]); // -5 是格式化输出左对齐
printf("\n");
return;
}
//遍历 1- n 如果访问过则继续循环呗
for(i = ; i <= n; i++) { if(vis[i]) continue;
vis[i] = ; //标记节点被访问过
a[s] = i; //在a 数组存取全排列的数字
dfs(s+); //深搜
vis[i] = ; //回溯操作,删掉节点访问痕迹
}
} int main() {
while() {
scanf("%d", &n);
if(!n) break;
memset(vis, , sizeof(vis));
dfs();
}
return ;
}
(二)全组合
建模:
给了数值n 对n 进行组合,并打印出。
思路:
1.输入n , 如果n不存在 返回。
2.dfs 找出n个数字的组合,用‘0’,‘1’标记法判断一个数字是否存在,并且对存在或者不存在依次进行递归。
3.若dfs次数>n,则输出组合的结果。
代码:
#include <stdio.h> int n, a[]; void dfs(int s) {
int i;
//输出排列后的结果
if(s > n) {
for(i = ; i <= n; i++) {
if(a[i])
printf("%-5d ", i);
}
return;
}
//对a[s]的存在亦或是不存在的两种情况进行递归。
a[s] = ;
dfs(s+);
a[s] = ;
dfs(s+);
} int main() { while() {
scanf("%d", &n);
if(!n) break;
dfs();
} return ;
}
(D89) The settlers of catan
建模:
已知n 个点,m 条边,输入两个点来构成一条边,构成一副无向图,两点之间可以有多条边,从任意一个点搜索,要求每条边只能经过一次,找到最长的路径。
思路:
1.输入点的个数n, 边的个数m,并且初始化存整个无向图的二维数组w
2.存边进入二维数组W
3.对所有点进行dfs搜索,如果路径最长则更新max
4.dfs找出所有存在的边,并且记录路径的长度
代码:
#include <stdio.h>
#include <string.h>
#define N 26 int w[N][N],max,n; //w[N][N] 存入整个图,w[i][j]=x 代表i到j有x条边 void dfs(int,int); int main()
{
int m,sum;
int a,b,i;
while()
{
scanf("%d%d",&n,&m);
if(!m && !n)
break; memset(w,,sizeof(w)); //初始化 for(i=;i<m;i++)
{
scanf("%d%d",&a,&b);
w[a][b]++; //无向图
w[b][a]++;
} max=;
for(i=;i<n;i++)
{
sum=; //把每个点作为出发点,对每一个点进行搜索
dfs(i,sum);
}
printf("%d\n",max);
}
return ;
} void dfs(int a,int sum) // a 为当前探索到哪一个节点,sum为当前探索到的路径长度
{
int i;
if(sum>max) //更新当前搜索到的最长路径
max=sum;
for(i=;i<n;i++)
{
if(w[a][i])
{
w[a][i]--; w[i][a]--; //用去一条边
dfs(i,sum+); // 进行下一层递归
w[a][i]++; w[i][a]++; //回溯到上一层 }
}
return;
}
(A38) A long stick
建模:
给了n个棍子的长度, 和b的值
找出一些棍子链接起来得到长度length, length >= b, length尽量接近b
思路:
1. min为结果, 初始化为所有棍子的长度和。
2. dfs找出这堆棍子的组合, 判断每一种组合所得到的长度sum, sum与min相比, 如果sum比min更优, 更新min为sum
优化:
1. 剪枝
a) 在当前搜索到的状态下, 假设剩下的棍子全部装完, 得到的结果 < b, 则可以剪枝.
b) 当搜索到的sum >= b时, 判断sum 与 min, 然后剪枝
2. 排序, 将棍子长度逆序排序, 在搜索的过程中, sum的增长速度会更快, 也可以提高剪枝效率。
未优化的代码:
#include <stdio.h> int n, b;
int len[];
int min; void dfs(int ,int); int main() {
int t, i;
scanf("%d", &t);//输入t次后结束
while(t--) { scanf("%d%d", &n, &b);//n为小棍子数目,b为拼接后的长度最接近的值
min = ;//拼接后趋近的结果
for(i = ; i < n; i++) {//输入n组小棍子长度
scanf("%d", &len[i]);
min += len[i];
} dfs(,);//递归求最接近b长度的若干根棍子合起来的长度值
printf("%d\n", min);//输出结果
} return ;
} void dfs(int sum, int i) { if(min == b) //假如拼接后的长度min 刚好为b 则返回
return;
if(sum >= b) {//如果棍子拼接的长度刚好>=b 如果比之前拼接的长度更接近于b,就更新min
if(sum < min)
min = sum;
return;
}
if(i == n) return;//避免死递归判断假如存在n的情况
dfs(sum+len[i], i+);//如果存在第i根棍子,往下搜索求和
dfs(sum, i+);//假设不存在第i根棍子,继续搜索求和
}
剪枝后的优化:
#include <stdio.h>
#include <string.h> int n, b;
int len[], s[];
int min; void dfs(int sum, int i); int main() {
int t, i;
scanf("%d", &t);
while(t--) { scanf("%d%d", &n, &b);
min = ;
memset(s, , sizeof(s));
for(i = ; i < n; i++) {
scanf("%d", &len[i]);
min += len[i];
}
for(i = n-; i > -; i--) //记录最后一根棍子 to 第i根棍子 的总长度
s[i] = s[i+] + len[i]; dfs(,);
printf("%d\n", min);
}
return ;
} void dfs(int sum, int i) {
if(min == b)
return;
if(sum >= b) {
if(sum < min)
min = sum;
return;
}
if(i == n) return;
if(sum+len[i]+s[i+] >= b ) //剪枝
dfs(sum+len[i], i+);
if(sum+s[i+] >= b) //剪枝
dfs(sum, i+); }
剪枝排序后的优化:
#include <stdio.h>
#include <string.h>
#include <stdlib.h> int n, b;
int len[], s[];
int min; void dfs(int sum, int i); int cmp(const void *a,const void *b)
{
return *(int *)b-*(int*)a;
} int main() {
int t, i;
scanf("%d", &t);
while(t--) { scanf("%d%d", &n, &b);
min = ;
memset(s, , sizeof(s));
for(i = ; i < n; i++) {
scanf("%d", &len[i]);
min += len[i];
} qsort(len,n,sizeof(len[]),cmp); for(i = n-; i > -; i--) //记录最后一根棍子 to 第i根棍子 的总长度
s[i] = s[i+] + len[i]; dfs(,);
printf("%d\n", min);
}
return ;
} void dfs(int sum, int i) {
if(min == b)
return;
if(sum >= b) {
if(sum < min)
min = sum;
return;
}
if(i == n) return;
if(sum+len[i]+s[i+] >= b ) //剪枝
dfs(sum+len[i], i+);
if(sum+s[i+] >= b) //剪枝
dfs(sum, i+); }
DFS 题目 用到的DFS函数:
// The Settlers of Catan V1 void dfs(int a,int sum)
{
int i;
if(sum>max) max=sum;
for(i=;i<n;i++) if(w[a][i]){
w[a][i]--; w[i][a]--;
dfs(i,sum+);
w[a][i]++; w[i][a]++;
} return;
}
// The Settlers of Catan V2 void dfs(int u, int num){
int flag;
for(int v=; v<n; ++v){
if(G[u][v] && !vis[u][v]){ if(G[u][v] != ){
flag = ;
vis[u][v] = ;
vis[u][v] = ;
G[u][v] --;
G[v][u] --;
}
else {
vis[u][v] = ;
vis[v][u] = ; } dfs(v, num+);
if(flag == ){
G[u][v]++;
G[v][u]++;
}
flag = ;
vis[u][v] = vis[v][u] = ;
}
} if(num > maxNum) maxNum = num;
}
// A long stick void dfs(int sum,int i)
{
int j;
sum-=stick[i];
if(sum<length || min==length)
return; if(sum<min)
min=sum; for(j=i+;j<=n;j++)
dfs(sum,j);
}
// repeatless V1 void dfs(int dep)
{
int i;
if (dep==)
{
int tmp=d[];
for (i=;i<=;i++) tmp=tmp*+d[i];
T++;
f[T]=tmp;
return;
}
if (T>) return;
for (i=;i<=;i++)
if (s[i]==)
{
d[dep+]=i;
sum+=i;
if (sum) s[i]++;
dfs(dep+);
if (sum) s[i]--;
sum-=i;
}
}
// repeatless V2 author : ZSX void recursion( int k )
{
if( bl == )
return ;
int i, j;
int a, b;
if( p == k )
{
int sum = ;
int temp;
for( i=; i<p; i++ )
{
temp = ;
for( j=; j<p-i-; j++ )
temp *= ;
sum += temp*buffer[i];
}
if( q <= )
array[q++] = sum;
else
bl = ;
}
else
{
for( a=; a<=; a++ )
if( flag[a] == && (p != || a!=) )
{
flag[a] = ;
buffer[p++] = a;
recursion( k );
flag[a] = ;
p--;
}
}
}
// 全排列 void dfs(int s, int n) {
int i;
if(s == n) {
for(i = ; i < n; i++)
if(i==) printf("%d", a[i]);
else printf(" %d", a[i]);
printf("\n");
return;
}
for(i = ; i <= n; i++) {
if(vis[i]) continue;
a[s] = i;
vis[i] = ;
dfs(s+, n);
vis[i] = ;
}
}
7.29 DFS总结的更多相关文章
- PAT天梯赛练习 L3-003 社交集群 (30分) DFS搜索
题目分析: 一共有N个编号为1~1000的人,以及一共有编号为1~1000种不同的兴趣,在题目给出1~N编号的人员每个人喜欢的兴趣的id后,要求统计出不同的人员集合的个数以及每个人员几个的人数从大到小 ...
- 回溯剪枝,dfs,bfs
dfs: 给定一个整数n,将数字1~n排成一排,将会有很多种排列方法. 现在,请你按照字典序将所有的排列方法输出. 输入格式 共一行,包含一个整数n. 输出格式 按字典序输出所有排列方案,每个方案占一 ...
- ACM: 强化训练-海贼王之伟大航路-dfs-枝减
海贼王之伟大航路 Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Descriptio ...
- hadoop默认3个核心配置文件说明
1 获取默认配置 配置hadoop,主要是配置core-site.xml,hdfs-site.xml,mapred-site.xml三个配置文件,默认下来,这些配置文件都是空的,所以很难知 ...
- hadoop三个配置文件的参数含义说明core-site.xml,hdfs-site.xml,mapred-site.xml
配置hadoop,主要是配置core-site.xml,hdfs-site.xml,mapred-site.xml三个配置文件,默认下来,这些配置文件都是空的,所以很难知道这些配置文件有哪些配置可以生 ...
- (转)hadoop三个配置文件的参数含义说明
hadoop三个配置文件的参数含义说明 1 获取默认配置 配置hadoop,主要是配置core-site.xml,hdfs-site.xml,mapred-site.xml三个配 ...
- hadoop三个配置文件的参数含义说明
1 获取默认配置 配置hadoop,主要是配置core-site.xml,hdfs-site.xml,mapred-site.xml三个配置文件,默认下来,这些配置文件都是空的,所以很难知 ...
- HDFS介绍及简单操作
目录 1.HDFS是什么? 2.HDFS设计基础与目标 3.HDFS体系结构 3.1 NameNode(NN)3.2 DataNode(DN)3.3 SecondaryNameNode(SNN)3.4 ...
- Hadoop生态集群之HDFS
一.HDFS是什么 HDFS是hadoop集群中的一个分布式的我文件存储系统.他将多台集群组建成一个集群,进行海量数据的存储.为超大数据集的应用处理带来了很多便利. 和其他的分布式文件存储系统相比他有 ...
随机推荐
- neu1458 方格取数 dp解法
题意: 有N * N个格子,每一个格子里有正数或者0,从最左上角往最右下角走,仅仅能向下和向右,一共走两次(即从左上角走到右下角走两趟),把全部经过的格子的数加起来,求最大值SUM,且两次假设经过同一 ...
- thinkphp学习笔记2—入口文件
原文:thinkphp学习笔记2-入口文件 在thinkphp中有两个入口文件,一个是项目的入口文件,是index.php在主目录里面,还有一个是thinkphp框架的的入口文件,放在框架目录下面如: ...
- 注册 集 与 删除 -- C
文章3位设置和清除操作. #include <stdio.h> #include <stdlib.h> #include <string.h> #define BI ...
- oracle_根据ID(字符型)建立分区表
方案思路:有一张暴增的数据表(10亿级别),以后需求需要提高单条查询性能, 这个表有个唯一ID, 假设是UUID,采用区分首字母的方法,不同字母的数据入到不同的物理文件中. 第一步: 查找数据库服务器 ...
- 对[yield]的浅究到发现[async][await]
原文:对[yield]的浅究到发现[async][await] 上篇对[foreach]的浅究到发现[yield]写完后,觉得对[yield]还没有理解清楚,想起曾经看过一位大牛的帖子讲的很深刻(链接 ...
- php正则函数学习
原文:php正则函数学习 <?php /** * php正则函数学习 * * 原来的ereg 和eregi 函数已经废弃掉了,目前版本用preg_match代替 * * preg_match 在 ...
- 点击鼠标获取元素ID
原文:点击鼠标获取元素ID public partial class Form1 : Form { public Form1() { InitializeComponent(); } private ...
- 随记一个C的毫秒级群PING
正好公司为了检测前台网络,力图收集有力证据与某CDN PK,所以随手写了一个群PING的程序. 写的内容比较简单,没有去特别追求线程效率,也没有去用LINUX 2.6+的殿堂级神器,以追求实现效率为主 ...
- 我的MYSQL学习心得(十二)
原文:我的MYSQL学习心得(十二) 我的MYSQL学习心得(十二) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYS ...
- C# 带滚动栏的Label控件
C# 带滚动栏的Label控件,用鼠标选的时候还是有点闪烁: namespace 带滚动栏的Label控件 { public class TextBoxLabel : System.Windows.F ...