題目鏈接
填空題
1. 12.5MB
【解題思路】
bit是位,B是字節,1B = 8bit,除此之外任意兩個都是1024的距離。
所以手機的4GB內存就是個字節(B)
【代碼】
//在計算機存儲中,12.5MB是多少字節?
#include<iostream>
using namespace std;
int main(){
int res = 12.5*1024*1024;
printf("%d", res);
return 0;
}
【結果】
13107200
2. 最多邊數
【解題思路】
n個結點的有向邊,那麼每個結點都可以連接另外n-1個結點,總共n個結點,那麼總邊數是
【代碼】
//一個包含有2019個結點的有向圖,最多包含多少條邊?(不允許有重邊)
#include<iostream>
using namespace std;
int main(){
int n = 2019;
printf("%d", n*(n-1));
return 0;
}
【結果】
4074342
3. 單詞重排
【解題思路】
STL的好處體現出來了。枚舉所有排列的另一個方法是從字典序最小排列開始,不停調用“求下一個排列”的過程。如何求下一個排列呢?C++的STL中提供了一個庫函數next_permutation。把所有排列都送到set集合中去重,最後輸出set的大小就行了。
比手算可快多了。
【代碼】
/*
將LANQIAO中的字母重新排列,可以得到不同的單詞。
如LANQIAO、AAILNOQ等,注意這7個字母都要被用上,單詞不一定有具體的英文意義。
請問,總共能排列如多少個不同的單詞。
*/
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
set<string> words;
string letters = "LANQIAO";
int main(){
sort(letters.begin(), letters.end());
do{
words.insert(letters);
// cout<<letters<<endl;
}while(next_permutation(letters.begin(), letters.end()));
cout<<words.size();
return 0;
}
【結果】
2520
4. 括號序列
【解題思路】
這個n = 4,看着挺小的自己在草稿紙上枚舉都行。但是遇到這種題要想着怎麼用代碼解決,因爲往往真到考試的時候就是靠手寫解決不了的規模。
用遞歸的思想寫一個DFS,參數應該包括當前處理的位置idx,比如4對括號要填8處,已經使用的左括號的個數ln,已經使用的右括號數rn。
下一個狀態的判斷:
- 只要表達式中左括號的個數大於等於右括號的個數,並且已經用的左括號沒超過可用的,就可以在idx處放左括號 ;
- 只要表達式中右括號的個數小於左括號的個數,並且已經用的右括號沒超過可用的,就可以在idx處放右括號;
遞歸邊界的判斷:
- 處理到了第位,從第0位開始填,0~剛好是個符號。
【代碼】
/*
由1對括號,可以組成一種合法括號序列:()。
由2對括號,可以組成兩種合法括號序列:()()、(())。
由4對括號組成的合法括號序列一共有多少種?
*/
#include<iostream>
using namespace std;
int n = 4; // n表示左括號和右括號的個數
int cnt = 0; //結果
void dfs(int idx, int ln, int rn){
// idx表示當前處理第幾位,ln、rn分別表示已經用了的左右括號個數
if(idx == 2*n){
cnt++;
return;
}
if( (ln >= rn) && (ln < n)){
//只要表達式中左括號的個數大於等於右括號的個數,並且已經用的左括號沒超過可用的,就可以在idx處放左括號
dfs(idx+1, ln+1, rn);
}
if( (rn < ln) && (rn < n)){
//只要表達式中右括號的個數小於左括號的個數,並且已經用的右括號沒超過可用的,就可以在idx處放右括號
dfs(idx+1, ln, rn+1);
}
}
int main(){
dfs(0, 0, 0);
printf("cnt:%d", cnt);
return 0;
}
【結果】
cnt:14
編程題
5. 反倍數
【解題思路】
放心枚舉。
【代碼】
/*
給定三個整數 a, b, c:
如果一個整數既不是 a 的整數倍也不是 b 的整數倍還不是 c 的整數倍。
則這個數稱爲反倍數,請問在 1 至 n 中有多少個反倍數。
*/
#include<iostream>
using namespace std;
int main(){
int n;
scanf("%d", &n);
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
int ans = 0;
for(int i=1; i<=n; i++){
if(i%a==0 || i%b==0 || i%c==0){
continue;
}
else{
ans++;
}
}
printf("%d", ans);
return 0;
}
6. 凱撒加密
【解題思路】
這種在一定範圍內循環的感覺就要善用%。
【代碼】
/*
給定一個單詞,請使用凱撒密碼將這個單詞加密。
凱撒密碼是一種替換加密的技術,單詞中的所有字母都在字母表上向後偏移3位後被替換成密文。
即a變爲d,b變爲e,...,w變爲z,x變爲a,y變爲b,z變爲c。
例如,lanqiao會變成odqtldr。
*/
#include<iostream>
#include<cstring>
using namespace std;
int main(){
string str;
cin>>str;
for(int i=0; i<str.length(); i++){
char ch = (str[i]-'a'+3) % 26 + 'a';
cout<<ch;
}
return 0;
}
7. 螺旋
【解題思路】
螺旋填數,這類題經常遇到。首先我們要確定並維持一個方向,就是當前填數的方向,然後朝這個方向填到底了,就轉90°繼續填。
本題中可以用四個整數0, 1, 2, 3分別表示右下左上,初始方向d = 0,然後d方向填到底,就順時針變換d++,因爲一直這麼順時針的轉,剛好是%。
朝着當前方向d走一步,經常用增量矩陣:
int direction[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上
爲了旋轉中判斷哪些框填過數了,用一個bool型的數組checked表示當前位置的框子是否有數了,那麼思路就清楚了,直接看代碼:
【代碼】
#include<iostream>
using namespace std;
const int maxn = 1010;
int num[maxn][maxn];
bool check[maxn][maxn] = {false};
int direction[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右下左上
int main(){
int n, m;
scanf("%d%d",&n, &m);
int pos_x, pos_y;
scanf("%d%d", &pos_x, &pos_y);
int x=1, y=1, times = 0;
// 0, 1, 2, 3分別表示右下左上
int d = 0;
int number = 1;
while(times < n*m){
if(!check[x][y]){
num[x][y] = number;
number++;
check[x][y] = true;
times++;
}
// 如果朝着d方向走一步不可行,就順時針改變方向。
if(x+direction[d][0] == n+1 || y+direction[d][1] == m+1 || x+direction[d][0] == 0 || y+direction[d][1] == 0){
d = (d+1)%4;
}
else if(check[x+direction[d][0]][y+direction[d][1]]){
d = (d+1)%4;
}
if(x == pos_x && y == pos_y){
break;
}
// 更新位置
x += direction[d][0];
y += direction[d][1];
}
printf("%d", num[pos_x][pos_y]);
return 0;
}
8. 擺動序列
【解題思路】
方法一:按照題意直接遞歸。當然過不了所有的樣例,但是思想簡單。
【代碼】
#include<iostream>
using namespace std;
const int maxn = 1010;
const int MOD = 10000;
int mem[maxn][maxn];
int m, n;
long long f(int cur, int pos){
// printf("%d %d\n", cur, pos);
if(mem[cur][pos] != 0){
return mem[cur][pos];
}
if(pos == m) return 1;
long long ans = 0;
if(pos%2){//cur在奇數列
for(int i=1; i<cur; i++){
ans = (ans + f(i, pos+1))%MOD;
}
}
else{
for(int i=cur+1; i<=n; i++){
ans = (ans + f(i, pos+1))%MOD;
}
}
mem[cur][pos] = ans;
return ans;
}
int main(){
scanf("%d%d", &m, &n);
long long ans = 0;
for(int i=2; i<=n; i++){
ans = (ans + f(i, 1)) % MOD;
}
printf("%lld", ans);
return 0;
}
方法二:爲了達到更多分,每次只拆開一層。
【代碼】
#include<iostream>
using namespace std;
const int maxn = 1010;
const int MOD = 10000;
int mem[maxn][maxn];
int m, n;
long long f(int cur, int pos){
// printf("%d %d\n", cur, pos);
if(mem[cur][pos] != 0){
return mem[cur][pos];
}
if(pos == m) return 1;
long long ans = 0;
if(pos%2){
//表示下一個數爲1~cur-1的序列個數
if(cur == 1) return 0;
//只拆一層,拆開下一個數爲cu1-1的一層
return mem[cur][pos] = (f(cur-1, pos) + f(cur-1, pos+1))%MOD;
}
else{
//表示下一個數爲cur+1~n的序列個數
if(cur == n) return 0;
//拆開下一個數爲cur+1的一層
return mem[cur][pos] = (f(cur+1, pos) + f(cur+1, pos+1))%MOD;
}
}
int main(){
scanf("%d%d", &m, &n);
long long ans = 0;
ans = f(1, 0);
printf("%lld", ans);
return 0;
}
9. 通電
prim算法,最小生成樹,模板題。
【代碼】
#include<iostream>
#include<cmath>
using namespace std;
const int maxn = 1010;
const double INF = 0x3fffffff;
double G[maxn][maxn];
struct node{
int x, y, h;
}graph[maxn];
int n;
double d[maxn];
bool vis[maxn];
double prim(){
fill(d, d+maxn, INF);
d[0] = 0;
double ans = 0;
for(int i=0; i<n; i++){
int u = -1;
double MIN = INF;
for(int j=0; j<n; j++){
if((!vis[j]) && d[j] < MIN){
u = j;
MIN = d[j];
}
}
if(u == -1) return -1;
vis[u] = true;
ans += d[u];
for(int v=0; v<n; v++){
if( (!vis[v]) && u != v && G[u][v] < d[v]){
d[v] = G[u][v];
}
}
}
return ans;
}
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d%d%d", &graph[i].x, &graph[i].y, &graph[i].h);
}
for(int i=0; i<n-1; i++){
for(int j=i+1; j<n; j++){
double x = pow(graph[i].x - graph[j].x, 2);
double y = pow(graph[i].y - graph[j].y, 2);
double h = pow(graph[i].h - graph[j].h, 2);
G[i][j] = G[j][i] = sqrt(x+y)+h;
}
}
// for(int i=0; i<n; i++){
// for(int j=0; j<n; j++){
// printf("%.2f ", G[i][j]);
// }
// printf("\n");
// }
double ans = prim();
printf("%.2f", ans);
return 0;
}
/*
4
1 1 3
9 9 7
8 8 6
4 5 4
0.000000 27.313708 18.899495 6.000000
27.313708 0.000000 2.414214 15.403124
18.899495 2.414214 0.000000 9.000000
6.000000 15.403124 9.000000 0.000000
*/