首页 > 其他分享 >Living-Dream 系列笔记 第7期

Living-Dream 系列笔记 第7期

时间:2024-03-09 12:33:51浏览次数:36  
标签:Living 格子 int 31 dfs 枚举 笔记 ans Dream

本期主要讲解深度优先搜索 \(\text{DFS}\)。

知识点

种类:

  • 全排列。可以想象为填格子。

  • 去重全排列,即组合。

时间复杂度均为 \(O(n!)\)。

\(\text{DFS}\) 题的特征:

  • 求方案总数 / 最值。

  • 数据范围极小(一般 \(n \le 20\))。

  • 无法直接暴力枚举(因为循环嵌套层数不确定)。

例题

T1

将每个人看作一个格子,枚举 \(1 \sim n\) 本书放入这些格子中,并且要满足当前处理的格子喜欢。

因此维护一个变量 \(x\),记录当前已经处理到了哪个格子。若 \(x+1=n\),则累加答案并 return 进行回溯,否则枚举每一本书尝试填入格子,若合法则进入下一层递归搜索。

注意需要使用 \(vis\) 数组记录每个数是否被用过,避免重复枚举。

跟普通的全排列搜索是没有什么区别的,只是多了一个限制条件。

#include<bits/stdc++.h>
using namespace std;

int n,ans;
int a[31],b[31];
bool vis[31];

void dfs(int x){
	if(x==n+1){
		ans++; return;
	}
	
	for(int i=1;i<=n;i++){
		if(!vis[i]&&(a[x]==i||b[x]==i)){
			vis[i]=1;
			dfs(x+1);
			vis[i]=0;
		}
	}
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	dfs(1);
	cout<<ans;
	return 0;
}

T2

此题属于第二种去重全排列搜索,它与第一种的区别在于,题目要求每组数都有序且不考虑顺序

既然如此,我们在枚举填哪个数时,就不能用 \(1 \sim n\),而应该用 \(a_{x-1}+1 \sim n\),即从上一个格子填的数 \(+ \ 1\) 开始循环。

#include<bits/stdc++.h>
using namespace std;

int n,r,ans[31];

void dfs(int x){
	if(x==r+1){
		for(int i=1;i<=r;i++) cout<<setw(3)<<ans[i];
		cout<<'\n';
		return;
	}
	for(int i=ans[x-1]+1;i<=n;i++) ans[x]=i,dfs(x+1);
}

int main(){
	cin>>n>>r;
	dfs(1);
	return 0;
}

T3

同样是第二种。

细节:

  • 循环需要从 \(\max{(1,a_{i-1})}\) 开始,到 \(n-1\) 结束,因为不能从 \(0\) 开始且允许重复使用数字且不能到 \(n\) 结束。

  • 注意此题的结束条件是所有数之和 \(sum=n\),但也要处理 \(sum>n\) 的情况。

#include<bits/stdc++.h>
using namespace std;

int n,ans[31];

void dfs(int x,int sum){
	if(sum==n){
		for(int i=1;i<x-1;i++) cout<<ans[i]<<'+';
		cout<<ans[x-1]<<'\n';
		return;
	}
	if(sum>n) return;
	
	for(int i=ans[x-1];i<n;i++){
		ans[x]=i;
		dfs(x+1,sum+i);
	}
}

int main(){
	cin>>n; ans[0]=1;
	dfs(1,0);
	return 0;
}

习题

T4

这题的 \(\text{DFS}\) 函数不仅要有 \(x\)、\(sum\),还要有 \(st\) 这个参数,表示循环的开始处,初始为 \(1\)。

每次搜索中循环 \(st \sim n\),对于每一个枚举到的 \(i\),继续进行 \(\text{DFS}\),并令 \(st \gets i+1\)。

其他的就和 T2 差不多了。

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,k,ans;
int a[31];

bool check(int x){
    if(x<2) return 0;
    for(int i=2;i*i<=x;i++) 
        if(x%i==0) return 0;
    return 1;
}
void dfs(int now,int sum,int st){
    if(now==k){
        if(check(sum)) ans++;
        return;
    }
    for(int i=st;i<=n;i++) 
        dfs(now+1,sum+a[i],i+1);
}

signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    dfs(0,0,1);
    cout<<ans;
    return 0;
}

T5

枚举 \(n\) 的全排列,依次验证,若合法则输出。注意 \(1,n\) 也是相邻的。

next_permutation 更简便。

#include<bits/stdc++.h>
using namespace std;

int n,ans;
int a[31];

bool P(int x){
    if(x<2) return 0;
    for(int i=2;i*i<=x;i++)
        if(!(x%i)) return 0;
    return 1;
}

int main(){
    cin>>n;
    for(int i=1;i<=n;i++) a[i]=i;


    do{
        bool f=1;
        for(int i=1;i<=n;i++){
            if(i<n)
                if(!P(a[i]+a[i+1])) f=0;
            if(i==n)
                if(!P(a[n]+a[1])) f=0; 
        }
        if(f){
            cout<<++ans<<':';
            for(int i=1;i<=n;i++) cout<<a[i]<<' ';
            cout<<'\n';
        }

    }while(next_permutation(a+1,a+n+1));
    cout<<"total:"<<ans;
    return 0;
}

标签:Living,格子,int,31,dfs,枚举,笔记,ans,Dream
From: https://www.cnblogs.com/XOF-0-0/p/18062523

相关文章

  • Living-Dream 系列笔记 第4期
    本期主要讲解二分答案。知识点使用场景:最小值最大化,或最大值最小化。在限制条件下找最值。与二分查找的区别:L、R均为答案,而非下标。输出:最大化输出L,反之输出R。例题T1二分\(M\)的值,边界为\(L=-1,R=\max{\{a_i\}}\)。每次枚举到一个\(mid\)就对于每个......
  • Living-Dream 系列笔记 第5期
    本期主要讲解二分答案的进阶。例题T1二分需要的秒数,在check函数中对于每件衣服,若其在\(x\)秒内无法自然晒干,则使用烘干机,并令\(sum\)加上使用烘干机的秒数,最后判断\(sum\)是否\(\lex\)即可。\(Trick\):二分边界需要按数据范围尽可能开大,不能开小了。#include<bits/......
  • 挑选一款适合自己的笔记本电脑的步骤
    你知道如何挑选一款适合自己的笔记本电脑吗?笔记本电脑有许多品牌和型号,因此挑选出合适的笔记本电脑是一项艰巨的任务。为了能够找到最适合你的笔记本电脑,你需要考虑一系列因素。需要先了解几个常见问题:·从什么渠道购买笔记本·笔记本电脑品牌都有哪些·购买笔记本首先弄清......
  • 3/9 训练笔记
    P5268[SNOI2017]一个简单的询问题解不妨把每个区间表示成\(|V|\)维向量\(b\)的形式,其中\(b[i]\)为在区间\([l,r]\)中,\(i\)出现的次数。然后我们发现要求的实际上是\(a\cdotb\)。拆一下(这里用\(g(i)\)表示\([1,i]\)的向量):\(a\cdotb=[l_1,r_1]\cdot[l_......
  • 课堂笔记2
    define_CRT_SECURE_NO_WARNINGSinclude<stdio.h>//////冒泡排序该方法只能进行整数的排序//voidBubbleSort(intarr[],intsz)//{//inti=0;//intj=0;//for(i=0;i<sz-1;i++)//{//for(j=0;j<sz-1-i;j++)......
  • 王道计算机网络截图笔记
    目录第一章概述1.计算机网络概览1.1网络与计算机网络1.2计算机网络的功能1.3计算机网络的组成1.3.1组成部分1.3.2工作方式1.3.3功能组成1.4计算机网络的分类1.5小结2.计算机网络的标准化工作2.1标准的分类2.2RFC2.3标准化工作的相关组织2.4小结3.计算机网络性能指标3......
  • 2024.3.9 笔记
    2024.3.9笔记P1948题目大意为在无向图上求出从\(1\)到\(N\)的路径,使路径上第\(k+1\)大的边权尽量少。第一种是DP用\(f[i][j]\)表示从\(1\)到点\(i\),用了\(j\)条免费线的最小花费。对于一条\(u->v\)的边\(e\)有转移:不用免费线\(f_{v,k}=min(f_{v,k},max......
  • MYSQl学习笔记19: 外键约束
    外键约束用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性具有外键的表(emp)称为子表外键关联的表(dept)称为父表外键约束创建表时添加createtable表名(字段名数据类型,[constrain][外键名称]foreignkey(外键字段名)references主表(主表......
  • MYSQL学习笔记20: 外键约束(删除/更新行为)
    外键约束删除/更新行为setdefault在mysql的默认引擎innodb中不支持CASCADEaltertable表名addconstraint外键名称foreignkey(外键字段)references主表名(主表字段名)onupdatecascadeondeletecascade;建立外键约束#如果父表和子表建立外键的字段有不同的......
  • MYSQL学习笔记17: 流程控制函数(IF, CASE)
    流程控制函数(IF,CASE)ifselectif(true,'ok','error');selectif(false,'ok','error');/*相当于iftrue:ok;else:error;*/ifnullselectifnull('ok','default');selectifnull(......