由数据范围反推时间复杂度
对C++而言,评测机1秒之内大概可以运行次 一般ACM或者笔试题的时间限制是1秒或2秒。 在这种情况下,C++代码中的操作次数控制在 为最佳
下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择
- 指数级别, dfs+剪枝,状态压缩dp
- floyd,dp,高斯消元
- dp, 二分, 朴素版Dijkstra, 朴素版Prim, Bellman-Ford
- 块状链表,分块,莫队
- 各种sort, 线段树, 树状数组, set/map, heap, 拓扑排序,Dijkstra+heap, Prim+heap, Kruskal, SPFA, 求凸包,求半平面交,二分,CDQ分治,整体二分,后缀数组,树链剖分,动态树
- 单调队列,hash,双指针扫描,BFS,并查集,KMP,AC自动机, 常数比较小的 sort, 树状数组,heap,dijkstra,SPFA
- 双指针扫描,KMP,AC自动机,线性筛素数
- 判断质数
- 最大公约数,快速幂,数位DP
- 高精度加减乘除
- k表示位数,高精度加减,FFT/NTT
所有递归=>递归搜索树
例题
AcWing92. 递归实现指数型枚举
个人题解
import java.util.*;
public class Main{
static Deque<Integer> path = new LinkedList<>();
static void dfs(int n, int index){
for(int i : path){
System.out.print(i+" ");
}
System.out.println();
for(int i = index; i <= n; ++i){
path.addLast(i);
dfs(n, i+1);
path.removeLast();
}
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
dfs(n,1);
}
}
标准题解
import java.util.*;
public class Main {
static int n;
/**
* 状态, 记录每个位置当前的状态:
* 0: 还没考虑
* 1: 选
* 2: 不选
*/
static int[] st;
static void dfs(int u){
if(u > n){
for(int i = 1; i <= n; ++i){
if(st[i] == 1) System.out.print(i + " ");
}
System.out.println();
return;
}
st[u] = 2;
dfs(u+1); //第一个分支: 不选u
st[u] = 0; //恢复现场
st[u] = 1;
dfs(u+1); //第二个分支: 选u
st[u] = 0;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
st = new int[n + 1];
dfs(1);
}
}
状态压缩
import java.util.Scanner;
public class Main {
static int n;
/**
* 状态, 记录每个位置当前的状态:
* 0: 不选
* 1: 选
*/
static int[] st;
static void dfs(int u){
if(u > n){
for(int i = 1; i <= n; ++i){
if(st[i] == 1) System.out.print(i + " ");
}
System.out.println();
return;
}
dfs(u+1); //第一个分支 不选
st[u] = 1;
dfs(u+1); //第二个分支 选
st[u] = 0;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
st = new int[n + 1];
dfs(1);
}
}
AcWing94. 递归实现排列型枚举
个人题解:
import java.util.Scanner;
public class Main {
static int n;
/**
* used[i]: i是否已经被使用
*/
static boolean[] used;
static int[] way;
static void dfs(int index){
if(index > n){
for (int i = 1; i <= n; i++) {
System.out.print(way[i] + " ");
}
System.out.println();
return;
}
for(int i = 1; i <= n; i++){
if(used[i]) continue;
used[i] = true;
way[index] = i;
dfs(index + 1);
used[i] = false;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
used = new boolean[n + 1];
way = new int[n + 1];
dfs(1);
}
}
习题
AcWing93. 递归实现组合型枚举
import java.util.*;
public class Main {
static int n;
static int m;
static int[] state;
/**
*
* @param index state的当前下标
* @param start 起始位置 [start,n]
*/
static void dfs(int index, int start){
if(index > m){
for (int j = 1; j <= m; ++j) {
System.out.print(state[j] + " ");
}
System.out.println();
return;
}
for(int i = start; i <= n - m + index; i++){
state[index] = i;
dfs(index+1, i+1);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
state = new int[m+1];
dfs(1, 1);
}
}
AcWing1209. 带分数
import java.util.Scanner;
public class Main {
static int n;
static boolean[] used;
static int count = 0;
static int[] permutation;
static int calc(int left, int right) {
int result = 0;
for(int i = left; i <= right; i++) {
result = result * 10 + permutation[i];
}
return result;
}
static void dfs(int index){
if(index > 9){
for(int i = 1; i <= 7; i++){
int a = calc(0, i);
for(int j = i + 2; j <= 9; j++){
int b = calc(i+1, j-1);
int c = calc(j, 9);
if(n * c == a * c + b) ++count;
}
}
return;
}
for(int i = 1; i <= 9; ++i){
if(used[i]) continue;
used[i] = true;
permutation[index] = i;
dfs(index+1);
used[i] = false;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
used = new boolean[10];
permutation = new int[10];
dfs(1);
System.out.println(count);
}
}