当前位置: 首页 > wzjs >正文

教育网站开发公司百度手机助手安卓版下载

教育网站开发公司,百度手机助手安卓版下载,有做网站设计的吗,邢台网站建设服务目录 前言 奶牛选美 分析 代码 大臣的旅费 分析 代码 飞机降落 分析 代码 母亲的牛奶 分析 代码 扫雷 分析 代码 前言 虽为诞辰,但也不忘完成每日的训练。 今天给大家带来五道dfs的题目,包括组合数,连通块,数的…

目录

前言

奶牛选美

分析

代码

大臣的旅费

分析

代码

飞机降落

分析

代码

母亲的牛奶

分析

代码

扫雷

分析

代码


前言

虽为诞辰,但也不忘完成每日的训练。

今天给大家带来五道dfs的题目,包括组合数,连通块,数的直径等方面的内容。

因为时间较为仓促,很多地方可能讲的不是很全面,请见谅。


奶牛选美

分析

题目保证图中存在且仅存在两个连通块,说实话这道题挺水的,不知道为什么难度是中等。

第一步,dfsbfs找出两个连通块。

随后的问题就是求两个连通块的最小曼哈顿距离,枚举两个连通块中的点,随后取最小值即可(这题题目的结果要减一)。

abs(x1 - x2) + abs(y1 - y2)

最后我们来分析一下时间复杂度,dfs或bfs的时间复杂度都是O(n ^ 2),求曼哈顿距离的时间复杂度是O(x * (n - x))x表示第一个连通块中的连通块数量),可以发现这是一个基本不等式,最大值为(n ^ 2) / 4,所以总的时间复杂度就是O(n ^ 2)。通过本题绰绰有余。


代码

// dfs连通块
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#define s second
#define f first
using namespace std;
typedef pair<int, int> PII;
const int N = 55;
int n, m;
char map[N][N];
bool read[N][N];
vector<PII> v[3];
int cnt;
int l = 0x3f3f3f3f;
PII s[] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};void dfs(int x, int y, vector<PII>& v)
{read[x][y] = true;v.push_back({x, y});for(int i = 0; i < 4; i++)if(map[x + s[i].f][y + s[i].s] == 'X' && !read[x + s[i].f][y + s[i].s])dfs(x + s[i].f, y + s[i].s, v);
}int main()
{scanf("%d%d", &n, &m);for(int i = 1; i <= n; i++)scanf("%s", map[i] + 1);for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)if(map[i][j] == 'X' && !read[i][j])dfs(i, j, v[cnt++]);for(PII a : v[0])for(PII b : v[1]){//printf("111");l = min(l, abs(a.s - b.s) + abs(a.f - b.f));}printf("%d", l - 1);return 0;
}

大臣的旅费


分析

从题目的描述中可以知道题目给的是一颗树。所以我们每次读取的边的数量就是n - 1(这个好像不用我说题目也说了)。而根据题目描述的所花路费只与总路程有关,路费是一个等差数列,所以对于这道题我们只需要求出路中的最长路径随后用n项和公式计算即可。

那么怎样求树中的最长路径呢?树的最长路径,其实就是树的直径

树的直径问题解法一边是使用两次dfs,一次找到离根节点(对于双向的树来说这个根可以是树中的任何点)最远的点,随后再用一次dfs遍历出的最长路径就是树的直径。

如何证明呢?

我们先来思考一下从一个点遍历一遍这棵树又回到起点的路径是多长,显而易见,这个路径长是边长和的二倍,在这条路中每条边是都被走了两遍的。

我们若想找到树中的直径显然是不能重复经过一条边的,所以直径要小于边长和的两倍

我们再思考,直径的理想情况是遍历树中的每一条边,这种情况是有可能的(一条直线),所以树的直径要小于等于树的边长和

铺垫完了这些我们就可以将求树的直径转化成树的边长和减去不经过的边长的长度,也就是:

d = l - x

d表示直径,l表示树边长之和,x表示未经过的边长,那么问题就转化成了求x的最小值

那么如何来求这个最小值呢?为方便理解,主包画了一个草图。

可以明显的看出直径就是最长的那一条(这是废话)。

我们按照我们的算法思路先以A为根节点找到D随后再一遍dfs找到C,那么从DC就是树的直径

为何这样是正确的呢?其实不难想,因为我们前面的分析,我们要求直径其实就是求避开的边长的最小值。

而我们在遍历树的过程中每次只记录距离最长的一条边(类似于dp),自然而然的就避开了所有短的边。

又根据树的性质两点之间的路径是唯一的,并且树中不存在环。所以就不存在图中那些弯弯绕,每次丢弃权重最小的一部分即可。

时间复杂度不必多说,两次都是O(n)


代码

/*树中的最长路,树的直径问题。先求长度,然后公式求解
*/
#include<iostream>
#include<vector>
#include<cstring>
#define s second
#define f first
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int N = 100010;
int n;
vector<int> tree[N];
vector<int> w[N];
bool read[N];
PII dfs(int v)
{PII l = {0, v};read[v] = true;for(int i = 0; i < tree[v].size(); i++){int z = tree[v][i];if(!read[z]){PII m = dfs(z);if(m.f + w[v][i] > l.f)l = {m.f + w[v][i], m.s};}}return l; //最长距离
}int main()
{scanf("%d", &n);for(int i = 1; i < n; i++){int x, y, z;scanf("%d%d%d", &x, &y, &z);tree[x].push_back(y);w[x].push_back(z);tree[y].push_back(x);w[y].push_back(z); }int i = dfs(1).s;memset(read, false, sizeof read);i = dfs(i).f;//printf("%d", i);printf("%lld", ((LL)i * (11 + 10 + i))/2);return 0;
}

飞机降落


分析

第一眼感觉是贪心,但是看到数据量之后发现不是贪心,数据量很小所以我们考虑搜索状态压缩dp

初步分析,总共有n太飞机,每台飞机都要在固定的区间内降落。

发现n很小,我们可以考虑组合数,而组合数的时间复杂度是n * n!这道题就是36288000,三千六百万,再乘上t就是3.6亿,时间限制是两秒钟。

虽然组合数的常数很小可能通过但是也有TLE的风险,考虑优化。

优化不必多说,搜索的常见优化就是打表和剪枝,对于组合数问题打表显然不行,所以我们考虑剪枝

我们枚举组合数就是枚举每台飞机降落的顺序,显然后面的飞机不可能在前面的飞机降落前完成降落,所以剪枝的判断条件就是后面的飞机能否在前面的飞机完成降落后降落

还有一步贪心就是如果这台飞机可以降落,我们该选择哪个时间使其降落。很好想尽量让开始降落的时间靠前(和线性dp很像)因为降落时间早的状态是包含降落时间晚的所有状态的。

剪枝后运行时间是38ms,说明我们的代码效率还是很高的。(实际剪枝后的时间复杂度是接近O(n ^ 2)的)


代码

/*全排列降落顺序即可
*/
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
const int N = 15;
int t, n;
int l[N], r[N], d[N];
vector<int> vtr;
bool read[N];bool dfs(int t) 
{if(vtr.size() == n)return true;for(int i = 1; i <= n; i++){if(!read[i]){if(l[i] + r[i] >= t) //可以放下{read[i] = true;vtr.push_back(i);if(dfs(max(t, l[i]) + d[i])) return true;read[i] = false;vtr.pop_back();}}}return false;
}
int main()
{scanf("%d", &t);while(t--){memset(read, false, sizeof read);vtr.clear();scanf("%d", &n);for(int i = 1; i <= n; i++)scanf("%d%d%d", l + i, r + i, d + i);if(dfs(0))puts("YES");elseputs("NO");}}

母亲的牛奶


分析

不得不吐槽一下这个名字好怪……

看完题目后发现数据量很小,分析一下能不能直接用搜索

初步分析的话是可以的,但是我们发现一个问题,那就是不知道搜索什么时候结束。

这个简单,因为每次倒牛奶都不会有损失也不会有增加,所以根据某某定理(主包忘了),在之后某一个时间点的状态一定会和当前状态完全相同。

也就是一个循环,所以我们只需要存储一下每次遍历到的状态,当发现重复遍历时退出即可。

分析一下时间复杂度,我们分析极限情况

每个桶的大小是小于等于20的,也就是每个桶有21种状态。所以总的状态量就是21 * 21 * 21,大概是一万,通过本题绰绰有余。


代码

#include<iostream>
using namespace std;
const int N = 22;
bool read[N][N][N]; //dfs遇到重复状态时就退出
bool C[N]; 
int a, b, c;
void dfs(int x, int y, int z)
{if(read[x][y][z]) return;read[x][y][z] = true;if(!x)  C[z] = true;//printf("%d %d %d", x, y, z);if(x != 0){dfs(max(0, x - (b - y)), min(b, y + x), z);dfs(max(0, x - (c - z)), y, min(c, z + x));}if(y != 0){dfs(min(a, x + y), max(0, y - (a - x)), z);dfs(x, max(0, y - (c - z)), min(c, z + y));}if(z != 0){dfs(min(a, x + z), y, max(0, z - (a - x)));dfs(x, min(b, y + z), max(0, z - (b - y)));}}int main()
{scanf("%d%d%d", &a, &b, &c);dfs(0, 0, c);for(int i = 0; i < 21; i++)if(C[i])printf("%d ", i);return 0;
}

扫雷


分析

今天的最后一道题(因为主包以前做过千奇百怪的扫雷游戏所以这种题感觉闭着眼睛都能写),不得不感慨,刷那么多题没记住几个,写着玩的东西倒是记忆犹新。

数据量是100 * 300 * 300,大概是1e7,所以我们需要将时间复杂度控制在线性

怎么写呢?我们先根据每个雷的位置处理出每个点应该有的数字,随后我们可以将0看为连通块,随后我们发现我们在点击非零块的时候一次只能解开一个,而在点击0时每次可以解开多个块(包括部分非0块)。

所以我们的思路是先解开0的连通块,随后再统计没有解开的非零块的数量即可。


代码

/*先找全0的连通块
*/
#include<iostream>
#include<cstring>
#define s second
#define f first
using namespace std;
typedef pair<int, int> PII;
const int N = 310;
int t, n;
char map[N][N];
bool read[N][N];
int st[N][N];
PII s[] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {1, 1}, {-1, 1}, {1, -1}};void init()
{for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(map[i][j] == '*')for(int k = 0; k < 8; k++)st[i + s[k].f][j + s[k].s]++; //统计数字
}void dfs(int x, int y)
{read[x][y] = true;if(st[x][y] == 0 && map[x][y] == '.'){for(int i = 0; i < 8; i++)if(!read[x + s[i].f][y + s[i].s]){read[x + s[i].f][y + s[i].s] = true;dfs(x + s[i].f, y + s[i].s); //dfs求连通块}}
}int main()
{scanf("%d", &t);for(int i = 1; i <= t; i++){memset(read, 0, sizeof read);memset(st, 0, sizeof st);scanf("%d", &n);for(int i = 1; i <= n; i++)scanf("%s", &map[i][1]);init();/*for(int i = 1; i <= n;puts(""), i++)for(int j = 1; j <= n; j++)printf("%d ", st[i][j]);*/int l = 0;for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(map[i][j] == '.' && !read[i][j] && st[i][j] == 0){//printf("%d %d\n", i, j);dfs(i, j);l++;}//printf("%d\n", l); for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(map[i][j] == '.' && !read[i][j])l++;printf("Case #%d: %d\n", i, l);}return 0;
}
http://www.dtcms.com/wzjs/156812.html

相关文章:

  • 衣服网站建设方案淘宝运营培训课程
  • 网站建设公司人员配备seo做的比较牛的公司
  • 网站建设金思扬网络网站seo收费
  • 整形网站建设方案策划书2023年8月疫情又开始了吗
  • 中山快速做网站服务站长之家ip地址查询
  • 做电子委托在那个网站宁波网络优化seo
  • 怎么在住房公积金网站做减员操作精准营销平台
  • 网站建设 代码下载打广告去哪个平台
  • 本地网站asp iis网站seo教材
  • 建筑设计方案大全海淀区seo搜索引擎优化企业
  • 虎丘网站建设苏州首页排名关键词优化
  • 网站设计策划书百度网站排名优化
  • 济宁网站建设济宁百度手机助手下载安装
  • 建网站的流程seo如何优化关键词排名
  • 如何做收费影视资源网站搜索引擎优化自然排名
  • 海口网约车最新政策合肥seo网络营销推广
  • 做微信请帖网站百度收录提交
  • 单位网站建设app拉新推广
  • 上海定制网站建设公司哪家好软文发稿平台有哪些
  • 一学一做教育视频网站有哪些东莞seo培训
  • 佛山北京网站建设公司哪家好微信朋友圈广告推广代理
  • 经典网站设计欣赏长春网站优化
  • 都网站建设查企业信息查询平台
  • 珠海企业网站制作费用手游推广赚佣金的平台
  • 有人拉我做彩票网站企业管理培训课程费用
  • 唐山正规做网站的公司seo销售代表招聘
  • 企业为什么需要网站职业技能培训班
  • 自己做的旅游网站简介广州企业网站seo
  • 福田企业网站推广公司网站发布流程
  • 建立本地网站百度seo优化推广