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

东莞哪家公司做网站比较好安阳网站制作哪家好

东莞哪家公司做网站比较好,安阳网站制作哪家好,做ppt赚钱的网站,360海南地方网站目录 前言 奶牛选美 分析 代码 大臣的旅费 分析 代码 飞机降落 分析 代码 母亲的牛奶 分析 代码 扫雷 分析 代码 前言 虽为诞辰,但也不忘完成每日的训练。 今天给大家带来五道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/578092.html

相关文章:

  • 包头市住房和城乡建设局网站运城网站建设公司有多少
  • 做快餐 承包食堂的公司网站做公司网站可以抄别人的吗
  • 网站建设es158wordpress网站数据库崩溃
  • 北京网站制作的公司网站开发项目架构
  • 网站制作 连云港有没有可以做翻译的网站
  • 企业怎么创建微信公众号长沙优化官网公司
  • 南山网站 建设seo信科dw网页制作下载
  • 电子商务网站的建设 论文wordpress登录失败
  • 网站页脚怎么做美观百度seo快速提升排名
  • 徐州seo建站广州哪些做网站的公司
  • 网站程序指的是什么什么是响应式网页
  • 做信息采集的网站阿里云做网站教程
  • 网站被黑了多久恢复做网站要服务器和什么软件
  • 汕头自助建站系统南阳网站建设口碑
  • 长春有免费做网站的么钓鱼网站如何做
  • 扁平化风格网站模板网站开发专业找什么工作
  • 国内优秀设计网站泰安新闻头条最新消息
  • 北京哪个网站制作公司企业网站的发展历史
  • 网站制作软件平台优化营商环境工作开展情况汇报
  • 站长工具官网查询电子商务网站总体规划的内容
  • 网站促销计算WordPress搭建流媒体网站
  • 浙江网站建设而网站备案进度
  • 公司自己怎么创建免费网站wordpress浏览器标签
  • 做网站的公司跑了深圳市网站建设有补贴吗
  • 网站建设考试多选题南宁中企动力
  • 北京中交建设工程咨询有限公司网站网站建设mvc三层框架图
  • 法治与安全做讲座网站广东公路建设公司官网
  • 百度云虚拟主机如何建设网站美妆网站开发背景
  • 现在做网站开发网站推广设计制作
  • 商务 服务类网站模板深圳大型网站建设服务