百練200題總結

百練200題總結

1. 有趣的跳躍 = 充分利用數組下標+再進行排序遍歷

題目描述

描述
一個長度爲n(n>0)的序列中存在“有趣的跳躍”當前僅當相鄰元素的差的絕對值經過排序後正好是從1到(n-1)。例如,1 4 2 3存在“有趣的跳躍”,因爲差的絕對值分別爲3,2,1。當然,任何只包含單個元素的序列一定存在“有趣的跳躍”。你需要寫一個程序判定給定序列是否存在“有趣的跳躍”。

輸入
一行,第一個數是n(0 < n < 3000),爲序列長度,接下來有n個整數,依次爲序列中各元素,各元素的絕對值均不超過1,000,000,000。
輸出
一行,若該序列存在“有趣的跳躍”,輸出"Jolly",否則輸出"Not jolly"。

結題思路

思路1(暴力):

  1. 計算原序列中第1個到第n-1個元素與其後面一個元素的差值的絕對值,依次存放在數組中。
  2. 對數組進行排序,遍歷數組是不是從1到n-1序列。
  3. 若遍歷時,數組元素不等於自增量,則輸出"Not jolly",並return 0;若遍歷完後沒有return 0,則輸出"Jolly"。

思路2(充分利用數組下標):

  1. 定義一個數組a,初始化爲0。
  2. 從輸入序列的第二個元素開始,直到最後一個元素,計算每一個元素與上一個元素的絕對值,記爲index,將a[index]賦值爲1
  3. 對a數組排序,遍歷數組a,看數組是否全部等於1。若不是,則輸出"Not jolly",若是,則輸出"Jolly"。

源代碼

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
	int n;
	if(cin >> n)
	{
		long long a[n];
		long long b[n-1];
		for(int i = 0; i < n; i++)
		{
			cin >> a[i];
		}
		for(int i = 0; i < n-1; i++)
		{
			b[i] = abs(a[i+1] - a[i]);
		}
		sort(b, b+n-1);
		for(int i = 0; i < n-1; i++)
		{
			if(b[i] != i+1)
			{
				cout << "Not jolly" << endl;
				return 0;
			}
		}
		cout << "Jolly" << endl;
	}
	return 0;
}
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	int n;
	int last, current;
	int a[3001] = {0};
	cin >> n;
	cin >> last;
	for(int i = 1; i < n; i++)
	{
		cin >> current;
		a[abs(current - last)]++;
		last = current;
	}
	for(int i = 1; i < n; i++)
	{
		//a數組若越界,也屬於此類 
		if(a[i] != 1)
		{
			cout << "Not jolly" << endl;
			return 0;
		} 
	}
	cout << "Jolly" << endl;
	return 0;
}

我的看法

此題可暴力求解,也可充分利用數組的下標,只有滿足相鄰元素的差值正好是從1到(n-1)時,才能正常地遍歷數組a,值越界或差不滿足從1到(n-1)時,都會輸出Not jolly。另外,方法1的複雜度爲nlogn2,方法2的複雜度爲n,方法2較快。

下次遇到此類題我要注意的地方

1.記錄a[i]=1,充分利用數組下標,進行遍歷,看value值是否都滿足要求。

充分利用數組的下標

此類題模板代碼

for(int i = 1; i < n; i++)
	{
		cin >> current;
		a[abs(current - last)]++;
		last = current;
	}

2. 瑪雅歷 = 兩個獨立循環 + 字符串比對函數

題目描述

描述

上週末,M.A. Ya教授對古老的瑪雅有了一個重大發現。從一個古老的節繩(瑪雅人用於記事的工具)中,教授發現瑪雅人使用了一個一年有365天的叫做Haab的歷法。這個Haab曆法擁有19個月,在開始的18個月,一個月有20天,月份的名字分別是pop, no, zip, zotz, tzec, xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu。這些月份中的日期用0到19表示。Haab歷的最後一個月叫做uayet,它只有5天,用0到4表示。瑪雅人認爲這個日期最少的月份是不吉利的,在這個月法庭不開庭,人們不從事交易,甚至沒有人打掃屋中的地板。

因爲宗教的原因,瑪雅人還使用了另一個曆法,在這個曆法中年被稱爲Tzolkin(holly年),一年被分成13個不同的時期,每個時期有20天,每一天用一個數字和一個單詞相組合的形式來表示。使用的數字是1~13,使用的單詞共有20個,它們分別是:imix, ik, akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix, mem, cib, caban, eznab, canac, ahau。注意:年中的每一天都有着明確唯一的描述,比如,在一年的開始,日期如下描述: 1 imix, 2 ik, 3 akbal, 4 kan, 5 chicchan, 6 cimi, 7 manik, 8 lamat, 9 muluk, 10 ok, 11 chuen, 12 eb, 13 ben, 1 ix, 2 mem, 3 cib, 4 caban, 5 eznab, 6 canac, 7 ahau, ,8 imix, 9 ik, 10 akbal ……也就是說數字和單詞各自獨立循環使用。

Haab歷和Tzolkin歷中的年都用數字0,1,……表示,數字0表示世界的開始。所以第一天被表示成:
Haab: 0. pop 0
Tzolkin: 1 imix 0
請幫助M.A. Ya教授寫一個程序可以把Haab歷轉化成Tzolkin歷。

輸入

Haab歷中的數據由如下的方式表示:
日期. 月份 年數

輸入中的第一行表示要轉化的Haab歷日期的數據量。下面的每一行表示一個日期,年數小於5000。

輸出

Tzolkin歷中的數據由如下的方式表示:
天數字 天名稱 年數

第一行表示輸出的日期數量。下面的每一行表示一個輸入數據中對應的Tzolkin歷中的日期。

結題思路

方法1:將Haab歷轉化爲一年中的第多少天,然後再轉成Tzolkin歷。

  1. 定義數組分別存放兩種曆法的月份、日期和Haab歷的天數。
  2. 根據輸入數據的格式,將每行輸入按照"%d. %s %d"的格式分別存到日,月,年中。按照兩種日曆的規則,將日月年按照計算規則轉化成第多少天,再轉化成Tzolkin歷。(這裏需要注意的是:Tzolkin歷的每一天用一個數字和一個單詞相組合的形式來表示,他們是各自獨立循環使用的,即:每一天都是day爲單位做循環,沒有月份的說法,其只是一個數字的代表。)

源代碼

#include <iostream>
#include <cstring>
using namespace std;
const int NAMELENGTH = 10;
int main()
{
	int n;
	int index;
	char HaabYue[19][NAMELENGTH] = {"pop", "no", "zip", "zotz", "tzec", "xul", "yoxkin", "mol", "chen", "yax", "zac", "ceh", "mac", "kankin", "muan", "pax", "koyab", "cumhu"};
	char TzolkinYue[20][NAMELENGTH] = {"imix","ik","akbal","kan","chicchan","cimi","manik","lamat","muluk","ok","chuen","eb","ben","ix","mem","cib","caban","eznab","canac","ahau"};	
	cin >> n;
	cout << n << endl;
	for(int j = 0; j < n; j++)
	{
		int days;
		int day, year;
		char month[NAMELENGTH];
		scanf("%d. %s %d", &day, month, &year);
		int i;
		for(i = 0; i < 19; i++)
		{
			if(!strcmp(HaabYue[i], month))
			{
				break;
			}
		}
		days = year * 365 + 20 * i + day;
		cout << days %  13 + 1 << " " << TzolkinYue[days % 20] << " " << days / 260 << endl;
	} 
	return 0;
}

意見

  1. 字符串比對函數strcmp():若兩個字符串相等,則返回0。用於if()中時,用!才能表示進入。
  2. Tzolkin歷相互不影響,獨立循環,總共可以表示260天。

下次遇到此類題我要注意的地方

1.字符串比對函數strcmp()。
  1. 定義字符二維數組來解決字符串比對問題。
  2. 特別注意細節之處,尤其是月份是否從0開始,需要遍歷多少次。
  3. 不知道爲什麼,我的代碼不能AC,但是測試用幾個用例都是能用的。需要得到解答!

此類題模板代碼

  1. 充分利用數組下標和value。
for(int i = 1; i < n; i++)
	{
		cin >> current;
		a[abs(current - last)]++;
		last = current;
	}

3. 走迷宮 = DFS + 防止回走 + 防止越界

題目描述

描述
一個迷宮由R行C列格子組成,有的格子裏有障礙物,不能走;有的格子是空地,可以走。
給定一個迷宮,求從左上角走到右下角最少需要走多少步(數據保證一定能走到)。只能在水平方向或垂直方向走,不能斜着走。
輸入
第一行是兩個整數,R和C,代表迷宮的長和寬。( 1<= R,C <= 40)
接下來是R行,每行C個字符,代表整個迷宮。
空地格子用’.‘表示,有障礙物的格子用’#‘表示。
迷宮左上角和右下角都是’.’。
輸出
輸出從左上角走到右下角至少要經過多少步(即至少要經過多少個空地格子)。計算步數要包括起點和終點。
樣例輸入

5 5
..###
#....
#.#.#
#.#.#
#.#..

樣例輸出
9

結題思路

方法1:深度優先搜索

  1. 輸入迷宮的長和寬。
  2. 定義一個二維字符數組a[R][C]表示迷宮。
  3. 從a[0][0]出發,調用深度優先的函數,傳入橫縱座標和步數。
  4. 在DFS函數中,判斷此座標爲最右下角,若是,則與目前最少的步數比較,將兩者的較小值賦值給minStep,並返回;若不是,則繼續判斷該座標是否越界或爲’#’,若滿足則返回。
  5. 設置此座標爲’#’(可避免往回走,同時可以一個visit數組來避免往回走),對其上下左右方向進行DFS,傳過去的步數是+1的。然後將此座標恢復爲’.’。
  6. 直到到達最右下角。

源代碼

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
char a[40][40]; 
int r, c;
int count = 0;
int minStep = 10000;
int visit[41][41];
void DFS(int i, int j, int step)
{
	if(i == r-1 && j == c-1)
	{
		minStep = min(minStep, step);
		return;
	}
	if( i < 0 || i > r-1 || j < 0 || j > c-1 || a[i][j] == '#')
	{
		return;
	}
	a[i][j] = '#';
	DFS(i-1, j, step+1);
	DFS(i+1, j, step+1);
	DFS(i, j-1, step+1);
	DFS(i, j+1, step+1);
	a[i][j] = '.';
}
int main()
{
	cin >> r >> c;
	for(int i = 0; i < r; i++)
	{
		for(int j = 0; j < c; j++)
		{
			cin >> a[i][j];
		}
	}
	DFS(0, 0, 1);
	cout << minStep << endl;
	return 0;
}

題型分析

  1. 此題屬於DFS,BFS類題,也是屬於圖類題。
  2. 以後要做一個搜索類題目的比較合集。
  3. 此題也可以用廣度優先搜索做,目前還沒有嘗試。

下次遇到此類題我要注意的地方

1.DFS要注意不能返回走,可設置a[i][j] = ‘#’,同時也可以設置一個visit數組來避免往回走。2.strcmp用於比較字符數組或兩個"aa"和"bb"是否相等。3. ==用來判斷同類型變量是否相等。
  1. strcmp只能比較兩個字符串是否相等,不能比較字符串和char類型(’'單引號表示char,雙引號表示字符串)。
  2. == 只能用於判斷兩個同類型的變量是否相等。
  3. 在處理搜索類型題目時,要注意增加是否越界的條件

此類題模板代碼

  1. DFS防止回走。
int visit[41][41];

或者

a[i][j] = '#';
	DFS(i-1, j, step+1);
	DFS(i+1, j, step+1);
	DFS(i, j-1, step+1);
	DFS(i, j+1, step+1);
	a[i][j] = '.';

4. 最大子序列和 = 只要是正數就相加

題目描述

結題思路

思路1:動態規劃的方法:求出每個位置的目前最大子序列和

  1. 從a[0]開始,比較當前最大子序列的和與其加下一個數,賦值給ans[i],得到每一個位置的最大子序列和。
  2. ans數組中最大的那個值即是結果。

源代碼

#include <iostream>
#include <stdlib.h>
#include <cmath>
using namespace std;

int main()
{
	int n;
	cin >> n;
	int *array, *ans;
	int cur_sum, max_sum;
	array = (int*)calloc(n+1, sizeof(int));
	for(int i = 0; i < n; i++)
	{
		cin >> array[i];
	}
	cur_sum = max_sum = array[0];
	for(int i = 1; i < n; i++)
	{
		cur_sum = cur_sum + array[i] > cur_sum ? cur_sum + array[i] : cur_sum;
		max_sum = max_sum > cur_sum ? max_sum : cur_sum;
	}
	cout << max_sum << endl;	
	return 0;
} 

題型分析

下次遇到此類題我要注意的地方

1.求出到每個位置爲止最大子序列和。

5. 最大上升子序列和 = 如果當前值大於j位置的數,並且他們組成的上升序列和更大。則更新i位置的最大值 + 兩層for循環 + if條件判斷 + calloc(stdlib.h)

題目描述

描述

一個數的序列bi,當b1 < b2 < … < bS的時候,我們稱這個序列是上升的。對於給定的一個序列(a1, a2, …,aN),我們可以得到一些上升的子序列(ai1, ai2, …, aiK),這裏1 <= i1 < i2 < … < iK <= N。比如,對於序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。這些子序列中序列和最大爲18,爲子序列(1, 3, 5, 9)的和.

你的任務,就是對於給定的序列,求出最大上升子序列和。注意,最長的上升子序列的和不一定是最大的,比如序列(100, 1, 2, 3)的最大上升子序列和爲100,而最長上升子序列爲(1, 2, 3)

輸入

輸入的第一行是序列的長度N (1 <= N <= 1000)。第二行給出序列中的N個整數,這些整數的取值範圍都在0到10000(可能重複)。

輸出

最大上升子序列和

樣例輸入

7
1 7 3 5 9 4 8

樣例輸出

18

結題思路

思路1:動態規劃的方法:找出第i個數(a)結尾的最大上升子串和。

  1. 需滿足三個條件:在i之前的&&數組a中小於a[i]&&ans的最大值
    (1)下標在i之前。for(int j = i-1; j >= 0; j–)
    (2)a[j] < a[i] (上升序列)
    (3)ans的最大值。
  2. 此i之前的最大上升子串和加上a[i] (此題中a[i]是大於0的)。

思路2:如果當前值大於j位置的數,並且他們組成的上升序列和更大。則更新i位置的最大值。

源代碼

#include <iostream>
#include <stdlib.h>
#include <cmath>
using namespace std;
int findMaxIncSum(int ans[], int i, int a[])//第i個數(a)結尾的最大子串和 
{
	int max = 0;
	for(int j = i-1; j >= 0; j--)//下標在i之前的&&數組a中小於a[i]的ans的最大值 
	{
		if(a[i] <= a[j])// 數組a中小於a[i]
		{
			continue;
		}
		else 
		{
			if(ans[j] > max)
			{
				max = ans[j];
			}
		}
	}
	return max + a[i];
}
int main()
{
	int n;
	cin >> n;
	int *array, *ans;
	int max_sum;
	array = (int*)calloc(n+1, sizeof(int));
	ans = (int*)calloc(n+1, sizeof(int)); 
	for(int i = 0; i < n; i++)
	{
		cin >> array[i];
	}	
	for(int i = 0; i < n; i++)
	{
		ans[i] = findMaxIncSum(ans, i, array);
	}
	max_sum = ans[0];
	for(int i = 1; i < n; i++)
	{
		max_sum = max_sum > ans[i] ? max_sum : ans[i];
	}	
	cout << max_sum << endl;
	return 0;
} 
#include<bits/stdc++.h> 
using namespace std;
int main(){
	int N,num[1010];
	int max[1010]; //存當前位置的最大上升序列的和 
	cin>>N;
	memset(max, 0, sizeof(max));
	for(int i = 0; i < N; ++i)	{
		cin>>num[i];
		max[i] = num[i];	//如果是非常大的數無法加入上升序列,可能其本身就是最優值 
	}

	for(int i = 1; i < N; ++i){
		for(int j = 0; j < i; ++j){
			if(num[i]>num[j]&&num[i]+max[j]>max[i]){	//如果當前值大於j位置的數,並且他們組成的上升序列和更大。則更新i位置的最大值 
					max[i] = num[i]+max[j];
			}
		}
	}
	int re = 0;
	for(int t:max)	re = re>t?re:t;		//從所有的序列最大值中找到最優解 
	cout<<re;
    return 0;
}

題型分析

  1. 動態規劃題,需要找出到每個位置爲止,a[j] < a[i] && 的最大上升子串之和。
  2. 此題中,a[i]是大於0的,若沒有此限制條件,則在findMaxIncSum中首先要判斷a[i]是否大於0,若小於則可以直接用上一個位置的最大上升子串和。
  3. 此類動態規劃題的關鍵是:找到"num[i]>num[j]&&num[i]+max[j]>max[i]"此條件,滿足此條件的則需要判斷。

下次遇到此類題我要注意的地方

1.動態規劃題,要特別注意改變某個位置最大值的條件
  1. 用calloc動態分配內存。
  2. 用動態規劃算法求出每個時刻的最大值。

此類題模板代碼


6. Yogurt factory = 要不要在上次生產時,多生產一些 + 用一個flag記錄上一次生產的日期(並更新)

題目描述

描述

The cows have purchased a yogurt factory that makes world-famous Yucky Yogurt. Over the next N (1 <= N <= 10,000) weeks, the price of milk and labor will fluctuate weekly such that it will cost the company C_i (1 <= C_i <= 5,000) cents to produce one unit of yogurt in week i. Yucky’s factory, being well-designed, can produce arbitrarily many units of yogurt each week.
在接下來的N周,牛奶和勞力的價格會波動,公司在第i周生產每單位酸奶的存儲費爲C_i美分。公司每週可以生產任意單位的酸奶。
Yucky Yogurt owns a warehouse that can store unused yogurt at a constant fee of S (1 <= S <= 100) cents per unit of yogurt per week. Fortuitously, yogurt does not spoil. Yucky Yogurt’s warehouse is enormous, so it can hold arbitrarily many units of yogurt.
繼續存儲每單位酸奶每週花費S美分存儲費,酸奶不會過期且能存無限量。
Yucky wants to find a way to make weekly deliveries of Y_i (0 <= Y_i <= 10,000) units of yogurt to its clientele (Y_i is the delivery quantity in week i). Help Yucky minimize its costs over the entire N-week period. Yogurt produced in week i, as well as any yogurt already in storage, can be used to meet Yucky’s demand for that week.
每週交付Y_i單位鮮奶,每週生產量i和存儲量均可用於出售

輸入

  • Line 1: Two space-separated integers, N and S.
    N周 S美分
  • Lines 2…N+1: Line i+1 contains two space-separated integers: C_i and Y_i.
    i周的存儲費C_i美分 每週交付量Y_i

輸出

  • Line 1: Line 1 contains a single integer: the minimum total cost to satisfy the yogurt schedule. Note that the total might be too large for a 32-bit integer.
    制定最好的生產計劃,當交付Y_i時,總花費最少

樣例輸入

4 5
88 200
89 400
97 300
91 500

樣例輸出

126900

提示

OUTPUT DETAILS:

In week 1, produce 200 units of yogurt and deliver all of it. In week 2, produce 700 units: deliver 400 units while storing 300 units. In week 3, deliver the 300 units that were stored. In week 4, produce and deliver 500 units.

結題思路

思路1:

  1. 第一週的牛奶自給自足。
  2. 第二週的牛奶判斷上一次(上一次生產的周不一定爲上週)的生產費用+上一次生產的周到此周所有單位牛奶所花的存儲費用是否大於此周的生產費用,若大於,則此周生產;若小於則上一次生產時多生產此周交付量的牛奶。
  3. 以後的週數以此類推。
  4. 輸出最後的sum。

源代碼

#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
long long c[10005], y[10005];
int main()
{
	int n, s;
	long long sum = 0;
	cin >> n >> s;
	for(int i = 0; i < n; i++)
	{
		cin >> c[i] >> y[i];
	} 
	sum = c[0] * y[0];
	int flag = 0;
	for(int i = 1; i < n; i++)
	{
		if(c[i] >= c[flag] + (i-flag) * s)
		{
			sum += (y[i] * c[flag] + (i-flag) * s * y[i]);
		}
		else 
		{
			sum += y[i] * c[i];
			flag = i;
		}
	}
	cout << sum << endl;
	return 0;
} 

題型分析

  1. (此解法是用貪心算法做的,但感覺其不一定是最優的。要用動態規劃做纔是最優的(設置兩個循環,並判斷最優條件)。)
  2. flag的設置,標誌爲上一次生產的週數。
  3. 貪心算法:判斷當選的選擇與之前最優的選擇誰更優,就選用哪種方法。

下次遇到此類題我要注意的地方

1.動態規劃貪心算法題,要特別注意改變某個位置最大值的條件(要不要在上次生產時,多生產一些)
  1. 英文題目;寫完中文翻譯之後,再去看英文,仔細理解題意。翻譯熟能生巧(看到英文界面不要怕,第一次做此種類型時,把它從頭到尾翻譯一遍,就知道到底是什麼水平了)。
  2. 貪心算法要善於找到最優的比較條件,如花費的錢最後(需追溯到數組的上幾位數)。

此類題模板代碼


7. 無線網絡 = 並查集問題 + 找父親函數 + 將已修復的電腦錶帶連接到同一個父親上(還需要做並查集的題)

題目描述

Description

An earthquake takes place in Southeast Asia. The ACM (Asia Cooperated Medical team) have set up a wireless network with the lap computers, but an unexpected aftershock attacked, all computers in the network were all broken. The computers are repaired one by one, and the network gradually began to work again. Because of the hardware restricts, each computer can only directly communicate with the computers that are not farther than d meters from it. But every computer can be regarded as the intermediary of the communication between two other computers, that is to say computer A and computer B can communicate if computer A and computer B can communicate directly or there is a computer C that can communicate with both A and B.

In the process of repairing the network, workers can take two kinds of operations at every moment, repairing a computer, or testing if two computers can communicate. Your job is to answer all the testing operations.

Input

The first line contains two integers N and d (1 <= N <= 1001, 0 <= d <= 20000). Here N is the number of computers, which are numbered from 1 to N, and D is the maximum distance two computers can communicate directly. In the next N lines, each contains two integers xi, yi (0 <= xi, yi <= 10000), which is the coordinate of N computers. From the (N+1)-th line to the end of input, there are operations, which are carried out one by one. Each line contains an operation in one of following two formats:

  1. “O p” (1 <= p <= N), which means repairing computer p.
  2. “S p q” (1 <= p, q <= N), which means testing whether computer p and q can communicate.

The input will not exceed 300000 lines.

Output

For each Testing operation, print “SUCCESS” if the two computers can communicate, or “FAIL” if not.

Sample Input

4 1
0 1
0 2
0 3
0 4
O 1
O 2
O 4
S 1 4
O 3
S 1 4

Sample Output

FAIL
SUCCESS

結題思路

思路1:並查集問題(設置flag和容器來解決)

  1. 初始化每臺電腦的位置,每臺電腦未修復的flag等於其序列i。
  2. 定義一個vector類型的容器,將每個電腦能連接的其他的電腦的序列i push_back進其容器。
  3. 當輸入’O’時,將此電腦修復,並將其錶帶相連到每一個已修復的電腦祖宗中(father[rooty] = rootx),即father[rooty]的座標值指向rootx
  4. 當輸入’S’時,判斷其最開始的祖宗是不是同一個,若是則輸出success,若不是則輸出fail。

源代碼

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstring>

#include <cmath>
using namespace std ; 

#define maxn 1010 
bool flag[maxn] ;
int father[maxn] ; 

vector<int> vv[maxn] ; 
int n , d ; 

struct node {
    int x , y ;
} post[maxn] ; 

double fun(int x){
    return x*x*1.0 ; 
}

void init(){
    memset(vv , 0 , sizeof(vv)) ; 

    for(int i=1 ; i<=n ; i++){
        father[i] = i ; //初始化 每臺電腦爲一個集合
        flag[i] = false ;// 所有電腦 初始狀態爲損壞 

        for(int j =1 ; j<=n ; j++){
            if(i==j){
                continue ; 
            }
            //爲 i 電腦 鏈接 所有 可連接距離內的電腦
            double dis = sqrt(fun(post[i].x-post[j].x)+fun(post[i].y-post[j].y)) ; 
            if(dis<=d){
                vv[i].push_back(j) ; 
            }
        }
    }
    for(int i = 0 ; i < n; i++)
	{
		cout << "vv" << i << ":";
		for(int j = 0; j < vv[i].size(); j++)
		{
			cout << vv[i][j];
		}
		cout << endl;
	}
}
//查詢 x 所在集合的代表元素的編號
//同時 理順集合內元素的關係(爲剛合併的兩個集合找出統一的代表)
int find(int x){
    if(x!=father[x])
        father[x] = find(father[x]) ; 
    return father[x] ; 
}

void Union_set(int x , int y){
    int rootx = find(x) ; 
    int rooty = find(y) ; 

    if(rootx != rooty){
        father[rooty] = rootx ; // 將 第二個集合的帶表元素 連接到第一個集合 
    }
}



int main(){

    while(~scanf("%d %d" , &n , &d)){
        for(int i=1 ; i<=n ; i++){
            scanf("%d%d" , &post[i].x , &post[i].y) ; 
        }
		
        init() ; 
        char str[3] ; 
        int x , y ; 

        while(~scanf(" %s" , str)){
            //scanf(" %s" , str) ; 

            if(str[0] == 'O'){
                scanf("%d" , &x) ; 
                flag[x] = true ; 
                for(int j=0 ; j<vv[x].size() ; j++){
                    int k = vv[x][j] ; 
                    if(flag[k]){//編號爲 k 的電腦已經被修復 
                        Union_set(x , k ) ; 
                    }
                }
            }else if(str[0] =='S'){
                scanf("%d %d" , &x , &y) ; 
                int rootx = find(x) ; 
                int rooty = find(y) ; 
                if(rootx == rooty){
                    printf("SUCCESS\n") ; 
                } else {
                    printf("FAIL\n") ; 
                }
            }
        }
        
    }
    return 0 ; 
}
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn  1005
bool flag[maxn];
int father[maxn];
struct node{
	int x, y;
}pos[maxn];
vector<int> vv[maxn]; // 容器數組 
int n, d; // $1. 全局變量的好處就是不用在函數中傳來傳去了。 
void initSet()
{
	memset(vv, 0, sizeof(vv));
	for(int i = 0; i < n ; i++)
	{
		cin >> pos[i].x >> pos[i].y;
	}
	for(int i = 0; i < n; i++)
	{
		flag[i] = 0; 
		father[i] = i; // 每個點爲自己的祖先 
		for(int j = 0; j < i; j++)
		{
			if(i == j)
			{
				continue;
			}
			if(pow((pos[i].x-pos[j].x), 2) + pow((pos[i].y-pos[j].y), 2) <= pow(d, 2))
			{
				vv[i].push_back(j);
			}
		}
	}
}

int getFather(int x)
{
	if(x != father[x])
	{
		father[x] = getFather(father[x]);
	}
	return father[x];
}

void becomeAFamily(int x, int y)
{
	int rootx = getFather(x);
	int rooty = getFather(y);
	if(rootx != rooty)
	{
		father[rooty] = rootx;
	}
}

int main()
{
	cin >> n >> d;
	initSet();
	char str[3];
	int x, y;
	while(~scanf(" %s", str))
	{
		if(str[0] == 'O')
		{
			scanf("%d" , &x) ; 
			flag[x] = 1;
			for(int j = 0; j < vv[x].size(); j++)
			{
				int k = vv[x][j];
				if(flag[k])
				{
					becomeAFamily(x, k);
				}
			}
		}
		if(str[0] == 'S')
		{
			cin >> x >> y;
			int rootx = getFather(x);
			int rooty = getFather(y);
			if(rootx == rooty)
			{
				cout << "SUCCESS" << endl;
			}
			else
			{
				cout << "FAIL" << endl;
			}
		}
	}
	return 0;
} 

題型分析

  1. 並查集問題,使用成爲"成爲家庭"和"找父親"的方法解決。

下次遇到此類題我要注意的地方

1.熟悉"成爲家庭"和"找父親"函數。
  1. 測試它的樣本是怎麼從出發到結束的。
  2. 特別注意所有的電腦都壞了,需要一個一個來修復;並且,當一個電腦修復後,其肯定能和其他。
  3. memset初始化數組、容器等。
  4. 代碼1,是不是應該還要考慮當x和k的祖宗不能成爲一家人時,就不需要進行集合的連接呢?這裏還需要考慮一下。
  5. 代碼2有一點問題,沒找出來。

此類題模板代碼

  1. 構造可達集合模板代碼
for(int i=1 ; i<=n ; i++){
        father[i] = i ; //初始化 每臺電腦爲一個集合
        flag[i] = false ;// 所有電腦 初始狀態爲損壞 

        for(int j =1 ; j<=n ; j++){
            if(i==j){
                continue ; 
            }
            //爲 i 電腦 鏈接 所有 可連接距離內的電腦
            double dis = sqrt(fun(post[i].x-post[j].x)+fun(post[i].y-post[j].y)) ; 
            if(dis<=d){
                vv[i].push_back(j) ; 
            }
        }
    }
  1. 找父親和並查集的模板代碼
//查詢 x 所在集合的代表元素的編號
//同時 理順集合內元素的關係(爲剛合併的兩個集合找出統一的代表)
int find(int x){
    if(x!=father[x])
        father[x] = find(father[x]) ; 
    return father[x] ; 
}

void Union_set(int x , int y){
    int rootx = find(x) ; 
    int rooty = find(y) ; 

    if(rootx != rooty){
        father[rooty] = rootx ; // 將 第二個集合的帶表元素 連接到第一個集合 
    }
}

8. Arctic Network = 距離的問題劃爲排序題 + 計算每個基站與前i-1個基站的距離存到動態數組中 + (int *)malloc(sizeof(int) * n)

題目描述

http://bailian.openjudge.cn/practice/2349/

結題思路

思路1:

  1. 每輸入一個基站座標時,計算其與前面i-1個基站的距離,存入distance數組中。
  2. 給distance數組排序,輸入v-sitelliteC的值。

源代碼

#include <iostream>
#include <cmath>
#include <iomanip>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int coordinate[501][2] = {0}; 
int main()
{
	int n;
	int *a;
	int sitelliteC, outpostC;
	double *distance;
	int v = 0;
	cin >> n;
	for(int i = 0; i < n; i++)
	{
		a = (int *)calloc(n, sizeof(int));
		//a = (int *)malloc(sizeof(int)*n);
		cin >> sitelliteC >> outpostC;
		distance = (double *)calloc(outpostC*(outpostC-1)/2, sizeof(double));
		for(int j = 0; j < outpostC; j++)
		{
			cin >> coordinate[j][0] >> coordinate[j][1];
			for(int p = 0; p < j; p++)
			{
				distance[v] = sqrt(pow(coordinate[j][0]-coordinate[p][0], 2) + pow(coordinate[j][1]-coordinate[p][1], 2));
				v++;
			}
			sort(distance, distance+v, greater<double>());
		}
//		for(int i = 0; i < v; i++)
//			{
//				cout << "distance[" << i << "]:" << distance[i] << endl;
//			}
//		cout << v << endl;
//		cout << sitelliteC << endl;
		cout << setiosflags(ios::fixed) << setprecision(2) << distance[v-sitelliteC] << endl;
	}
	return 0;
} 

題型分析

  1. c++格式輸出
#include <iomanip>
cout << setiosflags(ios::fixed) << setprecision(2) <<

下次遇到此類題我要注意的地方

1.setiosflags(ios::fixed) << setprecision(2)。2.sort()函數。

此類題模板代碼

  1. c++格式輸出
#include <iomanip>
cout << setiosflags(ios::fixed) << setprecision(2) <<
  1. sort函數模板
#include <algorithm>
sort(a, a+n, greater<>())

9. 數與字符串 = 從左到右對照每一個數排列,每一個數都儘量取最大的(9) + 整型與字符串的轉換(to_string()整型轉字符串 + itoa(num, a, 10)整型轉char [])

題目描述

http://bailian.openjudge.cn/xly2019/A/

結題思路

思路1:

  1. 輸入一個整數。
  2. 將整數轉化爲字符串,記位數爲len,並判斷此字符串的位數,若len爲1,則直接輸出此字符串。若大於1,則進入下一步。
  3. 判斷此字符串的最高位的情況,若最高位爲9,則是直接輸出輸出此字符串;若最高位不爲9,則輸出len-1位9。

源代碼

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
using namespace std;
int MAX = 10000; 
int main()
{
	string a[MAX];
	string res[MAX];
	int num;
	cin >> num;
	int i = 0;
	while(num != 0)
	{
		if(num < 10)
		{
			res[i] = to_string(num);
		}
		else
		{
			a[i] = to_string(num);
			if(res[i][0] == '9')
			{
				res[i] = a[i];
			}
			else
			{
				int len = a[i].length();
				int tmp = pow(10, len-1)-1;
				res[i] = to_string(tmp);
			}
			cin >> num;
			i++;
		}
	}
	for(int j = 0; j < i; j++)
	{
		cout << res[j] << endl;
	}
	return 0;
} 

題型分析

  1. 字符串和整型轉換題、夾雜着字典序。
  2. 字典序:從左到右對照每一個數排列,每一個數都儘量取最大的(9)。

下次遇到此類題我要注意的地方

  1. 對於string類型
    使用to_string(int value)將整型轉爲string類型。
  2. 對於char a[]
    使用itoa(int value, char * a, radix)將整型轉換爲char a[]。
  3. memset()的頭文件是cstring。
    ||易|中|難|
    |-|-|-|-|
    |緊||1. 字符串的轉換。2. 字典序。||
    |般||||
    |必||||

此類題模板代碼

  1. 整型轉string類型
res[i] = to_string(num);
  1. 整型轉char a[]型,char a[]轉string。
int num;
cin >> num;
char a[10];
// 整型轉char a[]型,itoa,a爲char a[]。
itoa(num, a, 10);
// char a[]轉string,直接賦值
string b = a;
cout << b;

題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


題目描述

結題思路

源代碼

題型分析

下次遇到此類題我要注意的地方

此類題模板代碼


<–>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章