ブルーブリッジカップ-2016年第7回C/C ++Zhenti[州大会][グループB]

コンテンツ

1.練炭の数(空欄に記入)

2.バースデーキャンドル(空欄に記入)

3.数式を作成します(結果を入力します)

4.クイックソート(空白をコードで埋める)

5.ロットを描画します(コードを入力します)

6.四角に記入します(結果に記入します)

7.スタンプをカットします(空欄に記入してください)

8. 4つの正方形の合計(プログラミングの質問)

9.ボトルを交換します(プログラミングの質問)

10.最大スケール(プログラミングの質問)

11.まとめ


1.練炭の数(空欄に記入)

三角錐の形に積み上げられた練炭の山があります。具体的
には、第1層に1
、第2層に3(三角形に配置)、
第3層に6(三角形に配置)、
第4層に10(三角形に配置)、

合計がある場合100層の合計、練炭はいくつですか?

練炭の総数を表す数字を入力してください。
注:提出物は整数である必要があり、余分なコンテンツや説明文を入力しないでください。

アイデア:問題を分析することでルールを見つけるのは簡単です。n番目の層の数=n-1層の数+n、1つの変数を使用して各層の変数の合計を格納し、別の変数を合計を保存します。別の方法は、この問題を再帰的に実行することです(再帰はアルゴリズムで非常に重要な役割を果たし、理解するのは簡単ではありません。遭遇するループを再帰に変更しようとします。時間の経過とともにマスターします。それ)

方法1:ループ

#include<iostream>
using namespace std;
int main()
{
	int n = 0;
	int sum = 0;
	for (int i = 1; i <= 100; i++)
	{
		n += i;
		sum += n;
	}
	cout << sum << endl;
	return 0;
}

方法2:再帰

#include<iostream>
using namespace std;
int f(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return f(n - 1) + n;
}
int sum(int n)
{
	if (n == 1)
	{
		return 1;
	}
	return f(n) + sum(n - 1);
}
int main()
{
	cout << sum(100) << endl;
	return 0;
}

 回答:171700

2.バースデーキャンドル(空欄に記入)

ある紳士は、ある年から毎年誕生日会を開いており、毎回同じ数のろうそくを吹き消さなければなりません。今数えて、彼は合計236本のろうそくを吹き消しました。すみません、彼は何歳で誕生日パーティーを始めましたか?彼が誕生日パーティーを始めた年齢を記入してください。注:提出物は整数である必要があり、余分なコンテンツや説明文を入力しないでください。

アイデア:この質問は簡単です。列挙するだけです(1-100) 

#include<iostream>
using namespace std;
int main()
{
	for (int i = 1;i <= 100; i++)
	{
		int sum = 0;
		for (int j = i; j <= 100; j++)
		{
			sum += j;
			if (sum == 236)
				cout << i << endl;
	 }
	}
	return 0;
}

3.数式を作成します(結果を入力します)

ここに画像の説明を挿入 

この式では、AIは19の数字を表し、異なる文字は異なる数字を表します。

例:
6 + 8/3 + 952/714は1つのソリューションであり、
5 + 3/1+972/486は別のソリューションです。

この方程式にはいくつの解がありますか?

注:提出物は整数である必要があり、余分なコンテンツや説明テキストを入力しないでください。

アイデア:この質問は非常に典型的な完全順列の問題です。1〜9の数値を格納する配列a [10]を定義してから、再帰バックトラックを介して完全順列を実行します。これは、テンプレートを直接記憶できる非常に一般的な再帰関数です。もちろん、next_permutationを直接使用して完全な順列を実行することもできます。完全な順列の後、この式が問題の条件(10に等しい)を満たしているかどうかを判断します。読者が次のチェックをよりよく理解できるようにするためです。機能、説明する絵を描きます。

コード:

#include<iostream>
#include<algorithm>
using namespace std;
int ants = 0;
int a[] = { 1,2,3,4,5,6,7,8,9 };
bool check()
{
	int x = a[3] * 100 + a[4] * 10 + a[5];
	int y = a[6] * 100 + a[7] * 10 + a[8];
	if ((a[1] * y + a[2] * x) % (a[2] * y) == 0 && a[0] + (a[1] * y + a[2] * x) /( a[2] * y) == 10)
	{
		return true;
	}
	else {
		return false;
	}
}
/*递归回溯生成全排列,适应于无重复元素的情况*/
void f(int k)
{
	if (k == 9)//一种排列已经生成
	{
		if (check())//检查该排列是否符合题意
		{
			ants++;
	  }
	}
	//从k往后的每个数都可以放在k的位置
	for (int i = k; i < 9; i++)
	{
		{int temp = a[i]; a[i] = a[k]; a[k] = temp; }
		f(k + 1);//递归
		{int temp = a[i]; a[i] = a[k]; a[k] = temp; //回溯
		}
	}
}
int main()
{
	f(0);
	//可以直接用next_permutation来完成
	/*do {
		if (check())
		{
			ants++;
		}
	} while (next_permutation(a, a + 9));*/
	cout << ants << endl;
	return 0;
}

4.クイックソート(空白をコードで埋める)

並べ替えは、さまざまな状況でよく使用されます。

クイックソートは非常に一般的で効率的なアルゴリズムです。
アイデアは次のとおりです。最初に「定規」を選択します。

キュー全体をふるいに通すために使用します。

確実にするために:左側の要素がそれより大きく、右側の要素がそれより小さくないこと。
このようにして、ソートの問題は2つのサブインターバルに分割されます。

次に、サブインターバルを個別に並べ替えることができます。
以下のコードは実装です。下線部分に不足しているコードを分析して入力してください。

#include <stdio.h>
 
void swap(int a[], int i, int j)
{
	int t = a[i];
	a[i] = a[j];
	a[j] = t;
}
 
int partition(int a[], int p, int r)
{
    int i = p;
    int j = r + 1;
    int x = a[p];
    while(1){
        while(i<r && a[++i]<x);
        while(a[--j]>x);
        if(i>=j) break;
        swap(a,i,j);
    }
	______________________;
    return j;
}
 
void quicksort(int a[], int p, int r)
{
    if(p<r){
        int q = partition(a,p,r);
        quicksort(a,p,q-1);
        quicksort(a,q+1,r);
    }
}
    
int main()
{
	int i;
	int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
	int N = 12;
	
	quicksort(a, 0, N-1);
	
	for(i=0; i<N; i++) printf("%d ", a[i]);
	printf("\n");
	
	return 0;
}

アイデア:クイックソートの全体的なアイデアに従って、関連するコードを分析するだけで済みます:while(i <r && a [++ i] <x) ;左のポインターがターゲット値よりも大きい数を見つけたことを示します、while(a [-j]> x) ;右ポインタがターゲット値よりも小さい数を検出したことを示します。f(i> = j)break ;小さな添え字i>=jの形成が終了することを示します。 .swap (a、i、j) ; Swap a [i]、a [j]逆の順序が復元されても、左小と右大の全体的な間隔に準拠します。上記の手順を実行すると、逆順序ペアが復元されたことを確認でき、プログラムは標準値Pを置き換える手順に進みます。プログラムでは、pが標準値、a [j]が標準値よりも小さい値、Pがa [0]であるため、swap(a、p、j)を交換します。次に、Pを最小値に置き換える必要があります。値なので、a[j]に置き換えます。

回答:swap(a、p、j);

5.ロットを描画します(コードを入力します)

惑星Xは5人の観測グループを惑星Wに送ります。その中で:国Aは最大4人を送ることができます。国Bは2人まで送ることができます。国Cは2人まで送ることができます。...。

では、スターWに送られる観測グループには、いくつの異なる国の組み合わせがありますか?

次のプログラムはこの問題を解決します。配列a[]は、各国が送信できる場所の最大数です。プログラムの実行結果は次のとおりです。

DEFFF

CEFFF

CDFFF

CDEFF

CCFFF

CCEFF

CCDFF

CCDEF

BEFFF

BDFFF

BDEFF

BCFFF

BCEFF

BCDFF

BCDEF

....

(以下省略,总共101行)

アイデア:この質問では、リターンがある場合はリターンがあり、以下に2つのforループがあることがわかります。したがって、再帰である可能性が高いと推測し、下を見て、 kは0であり、その終了条件は再びk = N(6)であり、kが継続的に増加し、mの初期値が5であり、最終的な出力条件が実際にm = 0であることを示します。したがって、mは絶えず縮小し、絶えず変化し、それらの形式を組み合わせる2つの変数がある場合、それは再帰的な式である必要があります。 

 1 #include <stdio.h>
 2 #define N 6
 3 #define M 5
 4 #define BUF 1024
 5 
 6 void f(int a[], int k, int m, char b[])
(数组a存放每个国家可以派出的人数;k表示国家个数,也作为深搜中外循环的条件;m表示剩下的人数;数组b存放情况的可能性)
 7 {
 8     int i,j;
 9     
10     if(k==N){ 
11         b[M] = 0;//这里是控制输出的字符串长度
12         if(m==0) printf("%s\n",b);
13         return;
14     }
15     
16     for(i=0; i<=a[k]; i++){//试着将k国家派出i个人
17         for(j=0; j<i; j++) b[M-m+j] = k+'A';
18         _____________;  //填空位置
19     }
20 }
21 int main()
22 {    
23     int  a[N] = {4,2,2,1,1,3};
24     char b[BUF];
25     f(a,0,M,b);
26     return 0;
27 }

 回答:f(a、k + 1、mi、b);  

6.四角に記入します(結果に記入します)

図に示すように、次の10個のグリッドには0から9までの数字が入力されています。要件:2つの連続した番号を隣接させることはできません。
(左右、上下、対角線上に隣接)可能な充填スキームはいくつありますか?
シナリオの数を表す整数を入力してください。

 

 アイデア:この質問に0〜9が記入されているのを見ました。最初に頭に浮かんだのは、完全順列問題の適用でした。また、この方法が上記で使用されているため、より感度が高い可能性があります。要約しました。上記のこのメソッドのテンプレートであり、変更するだけでよいチェック()関数を完了することができます。次に、本当に方法がない場合は、爆発的な検索もメソッドです。とにかく、それは空欄に記入する質問です。 。

方法1:完全な配置

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int ants ;
int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
bool check()
{
	if (abs(a[0] - a[1]) == 1 ||
		abs(a[0] - a[3]) == 1 ||
		abs(a[0] - a[4]) == 1 ||
		abs(a[0] - a[5]) == 1 ||

		abs(a[1] - a[2]) == 1 ||
		abs(a[1] - a[4]) == 1 ||
		abs(a[1] - a[5]) == 1 ||
		abs(a[1] - a[6]) == 1 ||
		abs(a[2] - a[5]) == 1 ||
		abs(a[2] - a[6]) == 1 ||
		abs(a[3] - a[4]) == 1 ||
		abs(a[3] - a[7]) == 1 ||
		abs(a[3] - a[8]) == 1 ||
		abs(a[4] - a[5]) == 1 ||
		abs(a[4] - a[7]) == 1 ||
		abs(a[4] - a[8]) == 1 ||
		abs(a[4] - a[9]) == 1 ||
		abs(a[5] - a[6]) == 1 ||
		abs(a[5] - a[8]) == 1 ||
		abs(a[5] - a[9]) == 1 ||
		abs(a[6] - a[9]) == 1 ||
		abs(a[7] - a[8]) == 1 ||
		abs(a[8] - a[9]) == 1)
		return false;
	return true;
}
void f(int k)
{
	if (k == 10)
	{
		if (check())
		{
			ants++;
		}
		return;
	}
	for (int i = k; i < 10; i++)
	{
		{int temp = a[i]; a[i] = a[k]; a[k] = temp; }
		f(k + 1);
		{int temp = a[i]; a[i] = a[k]; a[k] = temp; }
	}
}
int main()
{
	/*do {
		if (check())
		{
			ants++;
		}
	} while (next_permutation(a, a + 10));*/
	f(0);
	cout << ants << endl;
	return 0;
}

方法2:暴力的な捜索

#include<bits/stdc++.h>
using namespace std;

int a[4][5],visit[10];
int dx[4]={-1,-1,-1,0};
int dy[4]={0,1,-1,-1};
int sum;

bool check(int x,int y,int n){
    for(int i=0;i<4;i++){
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(xx<3&&xx>=0&&yy>=0&&yy<4){
            if(abs(a[xx][yy]-n)==1)
                return false;
        }
    }
    return true;
}

void dfs(int x,int y){
    if(x==2&&y==3){
        sum++;
        return;
    }
    for(int i=0;i<10;i++){
        if(visit[i]==0&&check(x,y,i)){
            visit[i]=1;
            a[x][y]=i;
            if(y+1<4)
                dfs(x,y+1);
            else
                dfs(x+1,0);//另起一行
            visit[i]=0;
        }
    }
}

int main(){
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            a[i][j]=-20;
    dfs(0,1);
    cout<<sum;
    return 0;
}

回答:1580 

7.スタンプをカットします(空欄に記入してください)

切手

[写真1.jpg]のように、12個の星座の切手が12個つながっています。
ここで、それらから5つを切り取る必要があり、要件を接続する必要があります。
(片方の角をつなぐだけでは繋がっているとはみなされません。)
例えば、[図2.jpg]と[図3.jpg]では、ピンク色で表示されている部分が修飾クリッピングです。

さまざまなクリッピング方法がいくつあるかを数えてください。

シナリオの数を表す整数を入力してください。
注:提出物は整数である必要があり、余分なコンテンツや説明文を入力しないでください。

 

アイデア:この質問はDFSディープサーチの実行方法を考えるのは簡単ですが、ディープサーチだけでは問題が発生し、「T」字型が表示され、ディープサーチを右方向と下方向に同時に行うことはできません。完全な配列を使用してから、それを2次元配列に入れ、詳細検索を使用して接続があるかどうかを判断し、コードに直接移動する必要があります:(完全な配置を手動で完了することはできないことに注意してください)ここでは、手書きの完全な配置で繰り返しがあり、この関数は繰り返しを生成しないため、next_permutationを使用する必要があります)

#include<iostream>
#include<algorithm>
using namespace std;
int ants;
int a[] = { 0,0,0,0,0,0,0,1,1,1,1,1 };
void dfs(int g[3][4],int x, int y)
{
	g[x][y] = 0;
	if (x - 1 >= 0 && g[x - 1][y] == 1)dfs(g, x - 1, y);
	if (x + 1 <= 2 && g[x + 1][y] == 1)dfs(g, x + 1, y);
	if (y - 1 >= 0 && g[x][y - 1])dfs(g, x, y - 1);
	if (y + 1 <= 3 && g[x][y + 1])dfs(g, x, y + 1);

}
bool check()
{
	int g[3][4];
	//将某个排列银蛇到
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (a[i * 4 + j] == 1)g[i][j] = 1;
			else   g[i][j] = 0;
		}
	}
	int cnt = 0;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (g[i][j] == 1)
			{
				dfs(g,i, j);
				cnt++;
			}
		}
	}
	return cnt == 1;
}
int main()
{
	do {
		if (check())
		{
			ants++;
		}
	} while (next_permutation(a, a + 12));
	cout << ants << endl;
	return 0;
}

回答:116 

8. 4つの正方形の合計(プログラミングの質問)

ラグランジュの定理としても知られる4平方和の定理:すべての正の整数は、最大4つの正の整数の2乗の合計として表すことができます。0を含めると、4つの数値の2乗の合計として表すことができます。例:5 = 0 ^ 2 + 0 ^ 2 + 1 ^ 2 + 2 ^ 2 7 = 1 ^ 2 + 1 ^ 2 + 1 ^ 2 + 2 ^ 2(^記号はパワーを意味します) 、二乗和の複数の表現が存在する可能性があります。4つの数値を並べ替えるように求められます:0 <= a <= b <= c<=d。そして、可能なすべての表現を、共同主キーとしてa、b、c、dに従って昇順で並べ替え、最後に最初の表現を出力します。プログラム入力は正の整数N(N <5000000)であり、スペースで区切られた、小さいものから大きいものへとソートされた4つの非負の整数を出力する必要があります。

たとえば、入力:
5
の場合、プログラムは次のように出力する必要があります:
0 0 1 2

別の例として、入力:
12
、プログラムは出力する必要があります:
0 2 2 2

別の例として、入力:
773535
、プログラムは次のように出力する必要があります:
1 1 267 838

リソースの規則:
ピークメモリ消費
量<256MCPU消費量<3000ms

要件に厳密に従って出力し、「入力してください...」のような余分なコンテンツを表面的に印刷しないでください。すべてのコードは同じソースファイルに配置され、デバッグ後、ソースコードをコピーして送信します。

注:main関数は0を返す必要があります。
注:ANSI C / ANSI C ++標準のみを使用し、コンパイル環境またはオペレーティングシステムに依存する特別な関数を呼び出さないでください。
注:すべての依存関数は、ソースファイルで明示的に#include <xxx>である必要があり、プロジェクト設定で共通ヘッダーファイルを省略できません。

送信するときは、目的のコンパイラタイプを選択するように注意してください。

アイデア:私たちが最初に考えるのは暴力的な列挙です。この方法は時間計算量が高く、実行タイムアウトが発生しますが、いくつかのポイントを得ることができます。時間計算量を減らす方法を見つける必要があります。この問題については、減らすことができます。 forループの時間計算量。時間計算量を減らすための時間。

コード:

#include<iostream>
#include<cmath>
#include<map>
using namespace std;
int main()
{
	int n;
	cin >> n;
	map<int, int> m;
	for (int c = 0;c* c <= n / 2; c++)
	{
		for (int d = c; c*c+d*d <= n; d++)
		{
			if (m.find(c*c + d*d) == m.end()) {
				m[c*c + d*d] = c;
			}
		}
	}
	for (int a = 0; a*a <= n / 4; a++)
	{
		for (int b = a; a*a+b*b <= n / 2; b++)
		{
			if (m.find(n - a*a -  b*b) != m.end())
			{
				int c = m[n - a*a - b*b];
				int d = (int)sqrt(n - a*a - b*b - c*c);
				cout << a << " " << b << " " << c << " " << d << endl;
				return 0;
			}
		}
	}
	return 0;
}

9.ボトルを交換します(プログラミングの質問)

棚には1〜Nの番号が付いたN本のボトルがあります。

たとえば、5本のボトルがあります:
2 1 3 5 4

一度に2本のボトルを拾い、それらの位置を交換するように依頼します。
数回後、ボトルのシリアル番号は次のようになります:
1 2 3 4 5

このような単純なケースでは、明らかに、リセットするには少なくとも2つのスワップが必要です。

もっとボトルがあったらどうしますか?プログラムで解決できます。

入力形式は2行です。1行目:
ボトルの数を示す正の整数N(N <10000)
。2行目:スペースで区切られたN個の正の整数。ボトルの現在の配置を示します。

出力データは正の整数の行であり、少なくともソートを完了するために何回交換するかを示します。

たとえば、次のように入力します
。5
3 1 2 5 4

プログラムは次のように出力する必要があります:
3

別の例として、次のように入力します
。5
5 4 3 2 1

プログラムは次のように出力する必要があります:
2

リソースの規則:
ピークメモリ消費量<256MCPU
消費量<1000ms

要件に厳密に従って出力し、「入力してください...」のような余分なコンテンツを表面的に印刷しないでください。

すべてのコードは同じソースファイルに配置され、デバッグ後、ソースコードをコピーして送信します。

注:main関数は0を返す必要があります。
注:ANSI C / ANSI C ++標準のみを使用し、コンパイル環境またはオペレーティングシステムに依存する特別な関数を呼び出さないでください。
注:すべての依存関数は、ソースファイルで明示的に#include <xxx>である必要があり、プロジェクト設定で共通ヘッダーファイルを省略できません。

送信するときは、目的のコンパイラタイプを選択するように注意してください。

アイデア:この質問は、バブルソート、逆順などで実行できますが、効率は比較的低いため、この質問を取り上げ、最初に配列を作成してから、a [i]==iが真であるかどうかを判断します。 、posを使用してiの位置を見つけ、それを交換します。

コード:

#include<iostream>
using namespace std;
int a[10001];
int n;
int ants;
int pos(int x)
{
	for (int i = 1; i <= n; i++)
	{
		if (a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
void swap(int i, int j)
{
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
int main()
{

	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++)
	{
		if (a[i] == i)
		{
			continue;
		}
		else {
			swap(pos(i), i);
			ants++;
		}
	}
	cout << ants << endl;
	return 0;
}

10.最大スケール(プログラミングの質問)

惑星Xの特定のグランプリにはMレベルの報酬があります。各レベルのボーナスは正の整数です。

また、隣接する2つのレベル間の比率は固定値です。

つまり、すべてのレベルのボーナス番号は比例シーケンスを形成します。

例:16,24,36,54

その等価比率は次のとおりです。3/2

今、私たちは勝者の賞数のいくつかをランダムに調査しました。

これに基づいて可能な最大等価値を計算してください。

入力フォーマット:

最初の行は数値N(N <= 100)であり、次の行にN個の正の整数が含まれていることを示します

2行目には、スペースで区切られたN個の正の整数Xi(Xi <1 000 000 000 000)が含まれています。各整数は、調査対象者に支払われるボーナスの金額を表します

リクエスト出力:

A / Bの形式の一部では、AとBが互いに素である必要があります。可能な最大の倍率を表します

テストデータは、入力形式が正しく、最大スケールが存在することを確認します。

入力 3
1250 200 32
4
3125 32 32200
3
549755813888 524288 2
出力 25/4 5/2 4/1

 アイデア:比例シーケンスの共通比率Xi <10 ^ 12を見つけ、最初にアイテムを並べ替え、ペアで分割し、分割します。各計算の結果が1より大きい限り、最後に残ったものが最大になります。公約数。N = 100、O(N * N)は許容範囲です。重複排除と共通比率が1の場合に注意する必要があります。

#include <cstdio>
#include <algorithm>
struct fs {
    __int64 fz, fm;
    bool operator == (const fs &B)const {
        if (B.fz != fz || B.fm != fm) return 0;
        return 1;
    }
}data[105];
__int64 rd[105];
__int64 GCD(__int64 a, __int64 b) {
    __int64 c;
    while (c = a%b) a = b, b = c;
    return b;
}
fs slv(fs a, fs b) {
    if (a == b) return a;
    __int64 gcd;
    gcd = GCD(a.fz, b.fz);
    a.fz /= gcd; b.fz /= gcd;
    gcd = GCD(a.fm, b.fm);
    a.fm /= gcd; b.fm /= gcd;
    a.fz *= b.fm;
    b.fz *= a.fm;
    if (a.fz > b.fz) a.fm = b.fz;
    else a.fm = a.fz, a.fz = b.fz;
    return a;
}
int main() {
    int i, j, n;
    scanf("%d", &n);
    for (i = 0; i < n; ++i) scanf("%I64d", rd + i), data[i].fm = 1;
    std::sort(rd, rd + n);
    for (i = j = 0; i < n; ++i) if (rd[i] != rd[i + 1]) data[j++].fz = rd[i];
    for (n = j - 1; n; --n) {
        for (i = 0; i < n; ++i) data[i] = slv(data[i], data[i + 1]);
    }
    if (j == 1) puts("1/1");
    else printf("%I64d/%I64d", data[0].fz, data[0].fm);
    return 0;
}

11.まとめ

01ブリケットの数の      簡単な計算
02誕生日キャンドル      算術シーケンスの合計
03算術式         の配置
04素早い並べ替えの      裸の質問
05抽選   による          再帰
06正方形と数字の完全な配置      +チェック
07接続されたブロックを見つけるためのカットスタンプ         +dfsの完全な配置マトリックス
084平方和      列挙+最適化(ハッシュキャッシュ)
09スワップボトル      貪欲
10最大スケール      演算、比例シーケンス前処理

おすすめ

転載: blog.csdn.net/m0_58367586/article/details/123709742