枚举
枚举范围:
- 枚举的边界要设定好
数据规模:
- 枚举要保证数据规模在时间限制内能够枚举完
枚举方式:
- 枚举顺序有时会影响时间
NOIP 2001 一元三次方程
问题描述
有形如:
a
x
3
+
b
x
2
+
c
x
+
d
=
0
ax^3+bx^2+cx+d=0
ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根 (根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)<0,则在(x1,x2)之间一定有一个 根。
样例
输入:1 -5 -4 20
输出:-2.00 2.00 5.00
枚举,用区间[-100, 100]枚举
#include<cstdio>
using namespace std;
const double eps=0.01;
double a,b,c,d;
int main() {
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
for(double x=-100.00;x<=100.00;x+=eps) {
double f=a*x*x*x+b*x*x+c*x+d;
if(f>=(-0.001) && f<=(0.001)) printf("%.2lf ",x);
}
return 0;
}
NOIP 2011 铺地毯
题目描述
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯,一共有n张地毯,编号从 1 到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。
输入
输入共 n+2行。
第一行有一个整数n,表示总共有 n张地毯。
接下来的 n行中,第 i+1行表示编号 i的地毯的信息,包含四个正整数 a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在 x轴和 y轴方向的长度。
第 n+2 行包含两个正整数 x 和 y,表示所求的地面的点的坐标(x,y)。
输出
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。
输入
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
输出
3
输入
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5
输出
-1
从最后一个地毯开始遍历,在这个正方形内,就输出,不再就往前一个地毯遍历
#include<bits/stdc++.h>
using namespace std;
int n,a[11000],b[11000],g[11000],k[11000],x,y;
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i++){
scanf("%d%d%d%d",&a[i],&b[i],&g[i],&k[i]);
}
scanf("%d%d",&x,&y);
for (int i = n;i >= 1;i--){
int you = a[i] + g[i];
int shang = b[i] + k[i];
if (x >= a[i] && y >= b[i] && x <= you && y <= shang){
printf("%d\n",i);
return 0;
}
}
printf("-1\n");
return 0;
}
DFS
框架
void dfs(参数)
{
if(越界或者不合法状态)return;
if(当前为终点/边界){
进行输出或计数统计答案等操作
return;//终止当前函数
}
for(枚举当前所有方案){
if(当前方案合法/当前方案没有被标记过){
记录当前方案标记当前方案
dfs(下一个位置)
还原标记
}
}
}
输出全排列
给出一个n,输出1-n的全排列
#include<bits/stdc++.h>
using namespace std;
const int MAX = 20;
bool marked[MAX];
int ans[MAX];
int n;
void dfs(int level){
if(level > n) {
for(int i=1; i<= n; i++){
printf("%d", ans[i]);
}
printf("\n");
return;
}
for(int i=1; i<=n; i++){
if(marked[i]) continue;
marked[i] = 1;
ans[level] = i;
dfs(level + 1);
marked[i] = 0;
}
}
int main(){
cin>>n;
dfs(1);
return 0;
}
经典寻路问题
题目
N个城市,编号 1 到 N 。城市间有 R 条单向道路。每条道路连接两个城市,有
长度和过路费两个属性。
Bob只有 K 块钱,他想从城市 1 走到城市 N 。问最短共需要走多长的路。如
果到不了 N ,输出 1
2<=N<=100; 0<K<=10000; 1<=R<=10000
每条路的长度L, 1 <= L <= 100; 每条路的过路费 T , 0 <= T <= 100
输入
输入的第一行包含整数K,0 <= K <= 10000,Bob可以在途中花费的最大硬币数。
第二行包含整数N,2 <= N <= 100,即城市总数。
第三行包含整数R,1 <= R <= 10000,道路总数。
以下R行中的每一行通过指定由单个空白字符分隔的整数S,D,L和T来描述一条道路:
S是源城市,1 <= S <= N.
D是目的地城市,1 <= D <= N.
L是道路长度,1 <= L <= 100
T是收费(以硬币数表示),0 <= T <= 100
请注意,不同的道路可能具有相同的源和目的地城市。
输出
输出的第一行和唯一一行应包含从城市1到城市N的最短路径的总长度,其总收费小于或等于K个硬币。如果此路径不存在,则只应将数字-1写入输出。
输入样例
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
输出样例
11
// dfs + 剪枝
- https://blog.csdn.net/yuanpengyuanpeng/article/details/105922842
加分二叉树
设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数。
若某个子树为空,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。要求输出;
(1)tree的最高加分
(2)tree的前序遍历
输入格式
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出格式
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
输入输出样例
输入样例#1:
5
5 7 1 2 10
输出样例#1:
145
3 1 2 4 5
BFS
二叉树的遍历
给出一个整数n ,表示一棵 n 个节点的二叉树,编号 1~n 。
根节点为1 号节点。接下来n 行每行给出两个整数 x,y 。表示节点 i 的左儿子和右儿子。 x=0 表示无左儿子,y=0 表示无右儿子。从1 号节点进行 BFS ,并输出遍历结果。
样例输入:
7
2 3
4 5
6 7
0 0
0 0
0 0
0 0
样例输出:
1 2 3 4 5 6 7
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2000;
struct node{
int le, re;
}t[MAXN];
void bfs(int level){
queue<int> q;
q.push(level);
while(!q.empty()){
int cur = q.front();
printf("%d ", cur);
q.pop();
if(t[cur].le) q.push(t[cur].le);
if(t[cur].re) q.push(t[cur].re);
}
}
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; i++){
scanf("%d%d", &t[i].le, &t[i].re);
}
bfs(1);
return 0;
}
马的遍历
题目描述
有一个n*m 的棋盘 (1<n,m<= 400),在某个点上有一个马 要求你计算出马到达棋盘
上任意一个点最少要 走几步
输入格式
一行四个数据,棋盘的大小和马的坐标
输出格式
一个n*m 的矩阵,代表马到达某个点最少要走几步(左对齐,宽 5 格,不能到达则输出 -1) 。
输入样例
3 3 1 1
输出样例
0 3 2
3 -1 1
2 1 4
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 500;
bool marked[MAXN][MAXN];
int ans[MAXN][MAXN];
int dx[10] = {0, -1, -1, 1, 1, 2, 2, -2, -2};
int dy[10] = {0, -2, 2, 2, -2, 1, -1, 1, -1};
int n, m, px, py;
struct node{
int x, y, v;
};
queue<node> q;
void bfs(node temp){
q.push(temp);
marked[px][py] = 1;
while(!q.empty()){
node cur = q.front();
q.pop();
int x = cur.x, y = cur.y, v = cur.v;
for(int i=1;i<=8;i++){
int xx = x + dx[i], yy = y + dy[i];
if(xx < 1 || yy < 1 || xx > n || yy > m) continue;
if(marked[xx][yy]) continue;
marked[xx][yy] = 1;
ans[xx][yy] = v + 1;
temp.x = xx, temp.y = yy, temp.v = v + 1;
q.push(temp);
}
}
}
int main(){
scanf("%d%d%d%d", &n, &m, &px, &py);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
ans[i][j] = -1;
ans[px][py] = 0;
node temp;
temp.x = px, temp.y=py, temp.v = 0;
bfs(temp);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
printf("%-5d", ans[i][j]);
}
if(i < n) printf("\n");
}
return 0;
}
双向BFS
走迷宫
八数码难题
状压搜索
砝码称重
虫食算