ブルーブリッジカップトレーニング1:実際の質問を検索(木の直径の方が興味深い)

質問1:混合数

トレーニング問題1:混合スコア

私のACコード:

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

int GetNum(int a[], int begin, int end) {
    
    
	int num = 0;
	for (int i = begin; i < end; ++i)
		num = num * 10 + a[i];
	return num;
}

int main() {
    
    
	int n, len = 0, a[9] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9 };
	cin >> n;
	int Temp = n, ans = 0;
	while (Temp) {
    
    
		Temp /= 10;
		len++;
	}
	do {
    
    
		int num = 0;
		for (int i = 0; i < len; ++i) {
    
    
			num = num * 10 + a[i];
			if(num >= n)
				break;
			int k = n, j = 9 - (i + 1);
			k -= num;
			int mid = (j >> 1) + 1;
			while (mid < 9) {
    
    
				int num1 = GetNum(a, i + 1, mid);
				int num2 = GetNum(a, mid, 9);
				if (0 == num1 % num2 && k == num1 / num2)
					ans++;
				mid++;
			}
		}
	} while (next_permutation(a, a + 9));
	cout << ans;
	return 0;
}

質問2:グリッドを切り取ります

トレーニング問題2:グリッドを切り取る

私のACコード:

#include <iostream>
using namespace std;

const int maxn = 12;
int n, m, a[maxn][maxn], vis[maxn][maxn], sum, ans;
int dir[4][2] = {
    
     {
    
    0, 1},{
    
    0,-1},{
    
    1,0},{
    
    -1,0} };
void dfs(int x, int y, int cnt, int blank) {
    
    
	if (cnt * 2 >= sum) {
    
    
		if (blank > ans && cnt * 2 == sum)
			ans = blank;
		return;
	}
	for (int i = 0; i < 4; ++i) {
    
    
		int dx = x + dir[i][0], dy = y + dir[i][1];
		if (dx >= 0 && dx < n && dy >= 0 && dy < m) {
    
    
			if (!vis[dx][dy]) {
    
    
				vis[dx][dy] = 1;
				dfs(dx, dy, cnt + a[dx][dy], blank + 1);
				vis[dx][dy] = 0;
			}
		}
	}
}
int main() {
    
    
	cin >> m >> n;
	for(int i = 0;i < n;++i)
		for (int j = 0; j < m; ++j)
		{
    
    
			cin >> a[i][j];
			sum += a[i][j];
		}
	if (sum & 1)
		cout << 0;
	else {
    
    
		dfs(0, 0, a[0][0], 1);
		cout << ans;
	}
	return 0;
}

3番目の質問:大臣の旅費

大臣の旅費

75点の純粋な暴力(タイムアウト):

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

const int maxn = 10005;
struct Edge {
    
    
	int dest, cost;
	Edge(int d, int c) :dest(d), cost(c) {
    
      }
};
vector<Edge> G[maxn];
int n, ans, cnt, vis[maxn];
int dfs(int p, int Len) {
    
    
	if (vis[p]) 
		return cnt;
	if (cnt < Len)
		cnt = Len;
	vis[p] = 1;
	for (int i = 0; i < (int)G[p].size(); ++i) 
		if (!vis[G[p][i].dest])
			dfs(G[p][i].dest, Len + G[p][i].cost);
	return cnt;
}
int main() {
    
    
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
    
    
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		G[a].push_back(Edge(b, c));
		G[b].push_back(Edge(a, c));
	}
	for (int i = 1; i <= n; ++i) {
    
    
		int Temp = dfs(i, 0);
		if (ans < Temp)
			ans = Temp;
		cnt = 0;
		memset(vis, 0, sizeof(vis));
	}
	printf("%d", ans * 10 + (ans + 1) * ans / 2);
	return 0;
}

アルゴリズムの分析:

この質問は木の直径を見つけることなので、このアルゴリズムについて話しましょう:木の直径

まず名詞を説明してください:木の直径

ツリーは特別なデータ構造であるため、ツリー上の任意の2つのポイントを相互接続でき、接続する方法は1つだけです。ツリーは最大の非循環グラフなので、最小の連結グラフです!次に、任意の2つのポイントを相互接続できるため、2つのポイント間の距離は、2つのポイントで構成されるすべてのポイントペアの中で最大でなければなりません。最大値を見つけることは木の直径を見つけることです!
どうやって?木の直径は被験者の特徴に合っていますか?

次に、アルゴリズムを説明します。dfsソリューションツリーの直径

まず真実を説明します:

任意の点から到達できる最も遠い点は、木の直径の終点でなければなりません!
どうして?これは反証される可能
性があります。木の直径の端から点pまでのパスがあるため、任意の点pが選択されているとします。端点がAおよびBであると想定します。pから到達できる最も遠い点がAまたはBではなくCである場合、次にA(またはB)から始めて、到達可能な最も遠いポイントはB(またはA)ではありません!あなたはこれを紙に描くことができ、あなたはそれを見つけるでしょう!

アルゴリズムのステップについて詳しく説明します。

最初のdfs:直径の端である開始点pから最も遠い点Aを見つけます
。2番目のdfs:直径の端から始めて、最も遠い点を見つけます。この距離が直径です!

このように、最初のn個のdfから2個のdfまで、合格できます!

私のACコード:

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

const int maxn = 10005;
struct Edge {
    
    
	int dest, cost;
	Edge(int d, int c) :dest(d), cost(c) {
    
      }
};
vector<Edge> G[maxn];
int n, ans = -1, MaxPoint = -1, vis[maxn];
void dfs(int p, int Len) {
    
    
	if (vis[p]) 
		return ;
	if (ans < Len) {
    
    
		ans = Len;
		MaxPoint = p;
	}
	vis[p] = 1;
	for (int i = 0; i < (int)G[p].size(); ++i) 
		if (!vis[G[p][i].dest])
			dfs(G[p][i].dest, Len + G[p][i].cost);
	return ;
}
int main() {
    
    
	scanf("%d", &n);
	for (int i = 1; i < n; ++i) {
    
    
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		G[a].push_back(Edge(b, c));
		G[b].push_back(Edge(a, c));
	}
	dfs(1, 0);
	ans = -1;
	memset(vis, 0, sizeof(vis));
	dfs(MaxPoint, 0);
	printf("%d", ans * 10 + (ans + 1) * ans / 2);
	return 0;
}

演習の概要:

正直に言うと、フロントエンドのほとんどの時間は、暗号化の研究とコーディングに費やされ、その後、オブジェクト指向プログラミングの実践に費やされています。私はしばらくの間アルゴリズムのトレーニングを行っていません(恥ずかしい!)。ブルーブリッジカップ、csp、ラダー競技、西安インビテーショナルなどの到着は、流行が終わった後に開催されますが、トレーニングを強化する必要があります。これらの質問は難しい検索トレーニングの質問ではありません。木の直径はより興味深く、注目に値します!

おすすめ

転載: blog.csdn.net/qq_44274276/article/details/104844474