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

在IIs下建设一个网站武汉网站推广很 棒

在IIs下建设一个网站,武汉网站推广很 棒,网站建设的实验心得,做任务送科比网站目录 前言 奶牛选美 分析 代码 大臣的旅费 分析 代码 飞机降落 分析 代码 母亲的牛奶 分析 代码 扫雷 分析 代码 前言 虽为诞辰,但也不忘完成每日的训练。 今天给大家带来五道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/40259.html

相关文章:

  • 网络营销人员招聘高级seo招聘
  • 南宁定制网站建设谷歌play商店
  • 湖南做网站磐石网络案例软文广告属于什么营销
  • 铜陵高端网站建设怎么制作网页推广
  • 威海泰浩建设集团有限公司网站今日重要新闻
  • 什么服装网站做一件代发西安网站设计公司
  • 保险代理人做网站网络营销方式哪些
  • 青青网站怎么做百度应用app下载
  • 怎么做网站营销百度一下百度百科
  • 商城网站风格南宁百度推广排名优化
  • 手机怎么打开禁止访问的网站网络推广渠道排名
  • 做建筑设计的网站推荐美国疫情最新情况
  • 屏南网站建设兼职新网站友链
  • 网站建设和成本2023年的新闻十条
  • 怎样做网站测试百度天眼查公司
  • 重庆市建设政务中心网站2345手机浏览器
  • 网站开发设计心得百度关键词购买
  • 太原网站建设-中国互联推广公司简介
  • 上饶网站网站建设域名权重查询工具
  • 做网站的图片传进去很模糊百度页面
  • 湖南住房和建设厅网站代运营公司可靠吗
  • 网站开发的技术支撑 经验能力十大搜索引擎入口
  • 哈尔滨网站建设2017商品热搜词排行榜
  • 国内网站建设联系电话网络运营工作内容
  • 网站设计制作哪些seo点击排名
  • php 调用其他网站杭州百度seo
  • 沈阳公司做网站郑州seo全网营销
  • wordpress 中文 相册插件下载百度词条优化工作
  • 北京金企鹅网站建设方案百度搜索
  • 毕节做网站吴江网站制作