11.24(46)

F - 环

#include <iostream>
#include <vector>
using namespace std;

const int N = 2e5;
int nxt[N], vis[N];
int start = -1;

void dfs(int u)
{
	vis[u]++;
	if (vis[u] == 2) {
		start = u;
		return;
	}
	dfs(nxt[u]);
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> nxt[i];
	}
	for (int i = 1; i <= n; i++) {
		if (vis[i] == 0) {
			dfs(i);
			if (start != -1) {
				break;
			}
		}
	}
	int u = start;
	vector<int>ans = { start };
	while (start != nxt[u]) {
		u = nxt[u];
		ans.push_back(u);
	}
	cout << ans.size() << endl;
	for (int x : ans) {
		cout << x << " ";
	}
	cout << endl;


	return 0;
}

解题流程:

1,先做,后做:

        第一步,定义全部变量

        (1)N题目规定的最大值

        (2)nxt数组:存输入的顶点顺序,vis数组是用来在DFS中判断是否出现了环

        (3)start:用来存环第一个顶点,初始值设为-1,后续方便用start是否==-1来判断是否出现环

        第二步,定义DFS函数

        (1)vis[x]++,表示x的遍历次数

        (2)如果vis[x]==2,说明出现了环,start=x,直接返回

        (3)否则,就调用递归函数dfs(nxt[x]),nxt[x]才是x指向的顶点

        第三步,main函数

        (1)输入nxt数组的元素,从1开始

        (2)循环遍历,如果vis[i]==0,那就递归调用dfs(i),当start!=-1时就是找到了一个环,这时就break循环

        (3)用u存储start的值,设置ans数组,用来存环的每一个顶点,第一个元素设为start

        (4)while(start!=nex[u])就更新u的值为nxt[u],并把u更新后的值push_back进ans数组

        (5)最后按照题目要求输出ans元素个数和每个元素

2,知识点套路:

        (1)深度优先搜索

        (2)环

3,前提条件:

        环

4,注意事项:

        (1)start最好设置一个初始值

        (2)不要搞混x和nxt[x]的含义

G - 滑冰

#include <iostream>
#include <string>
using namespace std;

string s[201];
int n, m;
int vis[201][201];
bool ok[201][201];
int dx[] = { 0,0,-1,1 };
int dy[] = { 1,-1,0,0 };

void dfs(int x, int y, int d)
{
	ok[x][y] = true;
	while (s[x + dx[d]][y + dy[d] ]!= '#') {
		x += dx[d];
		y += dy[d];
		ok[x][y] = true;
	}
	if (vis[x][y])return;
	else {
		vis[x][y] = 1;
		for (int i = 0; i < 4; i++) {
			dfs(x, y, i);
		}
	}
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> s[i];
		s[i] = '#' + s[i];
	}
	dfs(2, 2, 0);
	dfs(2, 2, 2);
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			ans += ok[i][j];
		}
	}
	cout << ans << endl;

	return 0;
}

解题流程:

1,先做,后做:

        第一步,初始化相关的变量:

        (1)201是题目限制的N,M的最大值+1,

        (2)n,m为图的行列,

        (3)vis二维数组是标记已经走过的点,

        (4)OK数组是标记的可达路径,一开始就在DFS中把ok[x][y]=true,是因为main里面调用第一遍函数的时候,传入的是(2,2),这个点一定是冰,而后面调用之前,都会判断过不是‘#’之后才标记为true

        (5)设置方向向量dx和dy,分别是上下左右变化时x,y的变化量

        第二步,写DFS函数

        (1)标记ok[x][y]为true,可达路径

        (2)循环遍历(深度优先搜索)一个方向,不是障碍物,就一直遍历,直到遇见障碍物,同时更新x,y的值

        (3)如果,此时vis[x][y]==1,那么说明这个点已经遍历过了,return

        (4)否则,就把这个点标记为已经遍历,即,vis[x][y]=1;在循环四次(四个方向)去调用DFS函数递归

        第三步,main函数:

        (1)传入n,m;并在循环输入s[i]后,加上一句,s[i]='#'+s[i],顺序不能调换,因为题目说了,周围边界都是障碍物,这里就是把每行的最左边都设置为障碍物,防止数组的越界行为

        (2)dfs(2,2,0),dfs(2,2,2),分别向是向上和向左搜索,只需要两个方向的就可以了(上+右、上+左、下+左、下+右)

2,知识点套路:

        (1)DFS深度优先搜素

        (2)用方向向量

3,前提条件:

         图

4,注意事项:

        (1)一定要在s数组的左边边界设置多一个#

        (2)

E - 串反转

#include <iostream>
#include <string>
#include <set>
#include <algorithm>
using namespace std;
int main()
{
	int n;
	cin >> n;
	set<string>unique_sticks;
	for (int i = 0; i < n; i++) {
		string s;
		cin >> s;
		string r_s = s;
		reverse(r_s.begin(), r_s.end());
		if (r_s < s) {
			unique_sticks.insert(r_s);
		}
		else {
			unique_sticks.insert(s);
		}
	}
	cout << unique_sticks.size() << endl;


	return 0;
}

解题流程:

1,先做,后做:

        (1)首先明白,题目的要求是要求不相同的三根根子,这时候应该要想到set,set可以自动去重

        (2)每输入一个String之后,我们都直接判断它和它的reverse哪个字典序小,我们把字典序小的Insert到set里面,set可以自动去重,最后set的元素数量就是我们要的

2,知识点套路:

        (1)set可以自动去重

        (2)reverse函数的调用

        (3)字典序

3,前提条件:

4,注意事项:

        (1)其实insert字典序大的也可以,只要选一种就行了

D - 一起度假

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	int n, d;
	cin >> n >> d;
	vector<string>vec(n+1);
	vector<bool>space(d + 1, true);
	for (int i = 1; i <= n; i++) {
		cin >> vec[i];
		string s = vec[i];
		for (int j = 0; j < s.length(); j++) {
			if (space[j + 1] == true && s[j] == 'o')space[j + 1] = true;
			else space[j + 1] = false;
		}
	}
	int count = 0;
	vector<int>ret;
	for (int i = 1; i <= d; i++) {
		if (space[i] == true) {
			count++;
		}
		else {
			ret.push_back(count);
			count = 0;
		}
	}
	ret.push_back(count);
	int m = 0;
	for (int i = 0; i < ret.size(); i++) {
		m = max(m, ret[i]);
	}
	cout << m << endl;

	return 0;
}

解题流程:

1,先做,后做:

        (1)先把Space初始设为true,只有Space[j+1]==true且s[j]=='o'的时候才能把这个位置的Space设置为true,因为要所有人都有空才能使公共的空余空间

        (2)连续的空闲天数可能有多个,要比较出最大的才输出

2,知识点套路:

3,前提条件:

4注意事项:

        (1)一定要分请各个变量名字,不要搞混——解决:自己定义变量名的时候要注意取一个自己不容易混的名字

        (2)要连续的天数,中最大的连续天数

        (3)在定义m之前要把此时的count  push进ret中,因为最后一个count没来得及push进去

C - 最小字典序

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
	string s;
	cin >> s;
	sort(s.begin(), s.end());
	cout << s << endl;

	return 0;
}

解题流程:

1,先做,后做:

2,知识点套路:字典序是什么,怎么比较大小的

3,前提条件:

4,注意事项: