藍橋杯__省賽__第八屆__C/C++__大學A組
目錄
1、迷宮
題意
X星球的一處迷宮遊樂場建在某個小山坡上。它是由10x10相互連通的小房間組成的。房間的地板上寫著一個很大的字母。我們假設玩家是面朝上坡的方向站立,則:
L表示走到左邊的房間,
R表示走到右邊的房間,
U表示走到上坡方向的房間,
D表示走到下坡方向的房間。
X星球的居民有點懶,不願意費力思考。他們更喜歡玩運氣類的遊戲。這個遊戲也是如此!開始的時候,直升機把100名玩家放入一個個小房間內。玩家一定要按照地上的字母移動。
迷宮地圖如下:
------------
UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR
------------
請你計算一下,最後,有多少玩家會走出迷宮?
而不是在裡邊兜圈子。
請提交該整數,表示走出迷宮的玩家數目,不要填寫任何多餘的內容。如果你還沒明白遊戲規則,可以參看一個簡化的4x4迷宮的解說圖:
思路
簡單模擬,按著路標進行移動。
C++程式
#include<iostream>
#include<cstring>
using namespace std;
char d[12][12];
int vis[12][12];//給陣列加了外圍一層,如果走到此處表示可以走出迷宮
void init()
{
for(int i=0;i<12;i++)
for(int j=0;j<12;j++)
{
if(i==0||i==11||j==0||j==11)
vis[i][j]=2;//走到最外圍一層,表示成功,我們用2來記錄
else
vis[i][j]=0;//0表示還未走到過此處
}
}
int main()
{
for(int i=1;i<=10;i++)
scanf("%s",d[i]+1);
int ans=0;
for(int i=1;i<=10;i++)
for(int j=1;j<=10;j++)//遍歷這100個人,模擬他們按路標走的過程
{
init();//初始化vis[][]陣列
bool flag=true;
int x=i,y=j;//(i,j)是當前這個人的起始位置
while(1)
{
vis[x][y]=1;//標記此人走到過位置(x,y)
//按路標向下一個位置走
if(d[x][y]=='L')//向左
y--;
else if(d[x][y]=='R')//向右
y++;
else if(d[x][y]=='U')//向上,注意是x--而不是x++
x--;
else
x++;//向下
if(vis[x][y]==1)//如果下一個位置已經走過,表示這個人走不出迷宮了
{
flag=false;
break;
}
else if(vis[x][y]==2)//如果vis[x][y]=2表示這個人走出迷宮
{
break;
}
}
if(flag) ans++;//如果這個人走出迷宮,結果加一
}
printf("%d\n",ans);
return 0;
}//31
答案
31
2、跳蚱蜢
題意
如圖所示:
有9只盤子,排成1個圓圈。其中8只盤子內裝著8只蚱蜢,有一個是空盤。我們把這些蚱蜢順時針編號為 1~8。每隻蚱蜢都可以跳到相鄰的空盤中,也可以再用點力,越過一個相鄰的蚱蜢跳到空盤中。請你計算一下,如果要使得蚱蜢們的隊形改為按照逆時針排列,並且保持空盤的位置不變(也就是1-8換位,2-7換位,...),至少要經過多少次跳躍?
注意:要求提交的是一個整數,請不要填寫任何多餘內容或說明文字。
思路
由於要求最小步數,因此使用 BFS
C++程式
#include<iostream>
#include<string>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
struct Node{
int pre,cur,step;//分別表示 前一個位置為pre,當前位置為cur,共花了step步
string s;//此時的狀態,用0表示空盤
Node(int pre,int cur,int step,string s):pre(pre),cur(cur),step(step),s(s){}
};
map<string,bool>vis;//標記這個狀態是否出現過
void bfs()
{
queue<Node>q;
q.push(Node(0,0,0,"012345678"));//壓入初始狀態
vis["012345678"]=true;//記錄此狀態已經出現過
while(!q.empty())
{
Node f=q.front();
q.pop();
if(f.s=="087654321")//如果達到要求的狀態,就輸出步數,並退出
{
printf("%d\n",f.step);
break;
}
int pos0=f.pre;//空位置在pos0處
int pos1=(pos0+1)%9;//相鄰的位置
string temp1=f.s;
swap(temp1[pos0],temp1[pos1]);
if(!vis[temp1])
{
q.push(Node(pos1,pos0,f.step+1,temp1));
vis[temp1]=true;
}
int pos2=(pos0-1+9)%9;//另一個相鄰的位置
string temp2=f.s;
swap(temp2[pos0],temp2[pos2]);
if(!vis[temp2])
{
q.push(Node(pos2,pos0,f.step+1,temp2));
vis[temp2]=true;
}
int pos3=(pos0+2)%9;//間隔一個的位置
string temp3=f.s;
swap(temp3[pos0],temp3[pos3]);
if(!vis[temp3])
{
q.push(Node(pos3,pos0,f.step+1,temp3));
vis[temp3]=true;
}
int pos4=(pos0-2+9)%9;//另一個間隔一個的位置
string temp4=f.s;
swap(temp4[pos0],temp4[pos4]);
if(!vis[temp4])
{
q.push(Node(pos4,pos0,f.step+1,temp4));
vis[temp4]=true;
}
}
}
int main()
{
bfs();
return 0;
}
//20
答案
20
3、魔方狀態
題意
二階魔方就是隻有2層的魔方,只由8個小塊組成。小明很淘氣,他只喜歡3種顏色,所有把家裡的二階魔方重新塗了顏色,如下:
前面:橙色
右面:綠色
上面:黃色
左面:綠色
下面:橙色
後面:黃色
請你計算一下,這樣的魔方被打亂後,一共有多少種不同的狀態。如果兩個狀態經過魔方的整體旋轉後,各個面的顏色都一致,則認為是同一狀態。
請提交表示狀態數的整數,不要填寫任何多餘內容或說明文字。
思路
C++程式
答案
4、方格分割
題意
6x6的方格,沿著格子的邊線剪開成兩部分。要求這兩部分的形狀完全相同。
如圖就是可行的分割法。試計算:包括這3種分法在內,一共有多少種不同的分割方法。注意:旋轉對稱的屬於同一種分割法。
請提交該整數,不要填寫任何多餘的內容或說明文字。
思路
DFS
C++程式
#include<iostream>
using namespace std;
const int N=6;
bool vis[N+1][N+1];
int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int ans;
void dfs(int x,int y)
{
if(x==0||x==N||y==0||y==N)
{
ans++;//到達邊界
return;
}
for(int i=0;i<4;i++)
{
int fx=x+d[i][0];
int fy=y+d[i][1];
if(vis[fx][fy]) continue;//這個點作為對稱點出現過了
vis[fx][fy]=true; //情況一:這個點在分割線上
vis[N-fx][N-fy]=true;//(fx,fy)的對稱點也必須在分割線上
dfs(fx,fy);
vis[fx][fy]=false;//情況二:這個點不在分割線上
vis[N-fx][N-fy]=false;//(fx,fy)的對稱點也不能在分割線上
}
}
int main()
{
vis[N/2][N/2]=true;
dfs(N/2,N/2);//從中心點(3,3)進行dfs
//一個圖案經過90,180,270度旋轉後都算作一個圖案
//而dfs的結果算作4個答案,因此要除以4
printf("%d\n",ans/4);
return 0;
}
答案
509
5、字母組串
題意
由 A,B,C 這3個字母就可以組成許多串。比如:"A","AB","ABC","ABA","AACBB" ....現在,小明正在思考一個問題:如果每個字母的個數有限定,能組成多少個已知長度的串呢?他請好朋友來幫忙,很快得到了程式碼,解決方案超級簡單,然而最重要的部分卻語焉不詳。
請仔細分析原始碼,填寫劃線部分缺少的內容。
#include <stdio.h>
// a個A,b個B,c個C 字母,能組成多少個不同的長度為n的串。
int f(int a, int b, int c, int n)
{
if(a<0 || b<0 || c<0) return 0;
if(n==0) return 1;
return ______________________________________ ; // 填空
}
int main()
{
printf("%d\n", f(1,1,1,2));
printf("%d\n", f(1,2,3,3));
return 0;
}
對於上面的測試資料,小明口算的結果應該是:
6
19
注意:只填寫劃線部分缺少的程式碼,不要提交任何多餘內容或說明性文字。
思路
第n個字母可以是一個‘A’或者是一個‘B’或者是一個‘C’。使用後相應的字元個數要減一,因此不難得出結果為
答案
f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1)
6、最大公共子串
題意
最大公共子串長度問題就是:求兩個串的所有子串中能夠匹配上的最大長度是多少。比如:"abcdkkk" 和 "baabcdadabc",
可以找到的最長的公共子串是"abcd",所以最大公共子串長度為4。下面的程式是採用矩陣法進行求解的,這對串的規模不大的情況還是比較有效的解法。請分析該解法的思路,並補全劃線部分缺失的程式碼。
#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
int a[N][N];
int len1 = strlen(s1);
int len2 = strlen(s2);
int i,j;
memset(a,0,sizeof(int)*N*N);
int max = 0;
for(i=1; i<=len1; i++){
for(j=1; j<=len2; j++){
if(s1[i-1]==s2[j-1]) {
a[i][j] = __________________________; //填空
if(a[i][j] > max) max = a[i][j];
}
}
}
return max;
}
int main()
{
printf("%d\n", f("abcdkkk", "baabcdadabc"));
return 0;
}
注意:只提交缺少的程式碼,不要提交已有的程式碼和符號。也不要提交說明性文字。
思路
最長公共子串 LCS
答案
7、正則問題
題意
考慮一種簡單的正規表示式:只由 x ( ) | 組成的正規表示式。小明想求出這個正規表示式能接受的最長字串的長度。例如 ((xx|xxx)x|(x|xx))xx 能接受的最長字串是: xxxxxx,長度是6。
輸入
----
一個由x()|組成的正規表示式。輸入長度不超過100,保證合法。
輸出
----
這個正規表示式能接受的最長字串的長度。
例如,
輸入:
((xx|xxx)x|(x|xx))xx
程式應該輸出:
6
資源約定:
峰值記憶體消耗(含虛擬機器) < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
注意:
main函式需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要呼叫依賴於編譯環境或作業系統的特殊函式。
所有依賴的函式必須明確地在原始檔中 #include <xxx>
不能通過工程設定而省略常用標頭檔案。
提交程式時,注意選擇所期望的語言型別和編譯器型別。
思路
DFS
C++程式
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int k=0;
string s;
int dfs()
{
int ans=0,result=0;
while(k<s.length())
{
if(s[k]=='(')//開始一個新的搜尋
{
k++;
ans+=dfs();
}
else if(s[k]==')')
{
k++;
break;//停止此次搜尋
}
else if(s[k]=='|')
{
k++;
result=max(ans,result);
ans=0;
}
else
{
k++;
ans++;
}
}
result=max(result,ans);//遇到(break後需要進行一次比較
return result;
}
int main()
{
cin>>s;
cout<<dfs()<<endl;
return 0;
}
8、包子湊數
題意
小明幾乎每天早晨都會在一家包子鋪吃早餐。他發現這家包子鋪有N種蒸籠,其中第i種蒸籠恰好能放Ai個包子。每種蒸籠都有非常多籠,可以認為是無限籠。每當有顧客想買X個包子,賣包子的大叔就會迅速選出若干籠包子來,使得這若干籠中恰好一共有X個包子。比如一共有3種蒸籠,分別能放3、4和5個包子。當顧客想買11個包子時,大叔就會選2籠3個的再加1籠5個的(也可能選出1籠3個的再加2籠4個的)。當然有時包子大叔無論如何也湊不出顧客想買的數量。比如一共有3種蒸籠,分別能放4、5和6個包子。而顧客想買7個包子時,大叔就湊不出來了。小明想知道一共有多少種數目是包子大叔湊不出來的。
輸入
----
第一行包含一個整數N。(1 <= N <= 100)
以下N行每行包含一個整數Ai。(1 <= Ai <= 100)
輸出
----
一個整數代表答案。如果湊不出的數目有無限多個,輸出INF。
例如,
輸入:
2
4
5
程式應該輸出:
6
再例如,
輸入:
2
4
6
程式應該輸出:
INF
樣例解釋:
對於樣例1,湊不出的數目包括:1, 2, 3, 6, 7, 11。
對於樣例2,所有奇數都湊不出來,所以有無限多個。
資源約定:
峰值記憶體消耗(含虛擬機器) < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
注意:
main函式需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要呼叫依賴於編譯環境或作業系統的特殊函式。
所有依賴的函式必須明確地在原始檔中 #include <xxx>
不能通過工程設定而省略常用標頭檔案。
提交程式時,注意選擇所期望的語言型別和編譯器型別。
思路
擴充套件歐幾里得變形+完全揹包。
定理一:如果所有數的最大公約數不為1則有無窮個,否則都是有限個。
定理二:如果湊不出的數為有限個,則當數大於某個值時就都能湊出來。
使用完全揹包統計哪些數能夠被湊出來。
C++程式
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int n,int m)
{
return m==0?n:gcd(m,n%m);
}
const int N=105;
const int MAX=100005;
int n;
int a[N];
bool able[MAX];
void maketable()
{
able[0]=true;
for(int i=0;i<n;i++)
{
for(int j=0;j+a[i]<MAX;j++)
if(able[j])
able[j+a[i]]=true;
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int g=a[0];
for(int i=1;i<n;i++) g=gcd(g,a[i]);
if(g!=1)
{
printf("INF\n");
return 0;
}
maketable();
int ans=0;
for(int i=0;i<MAX;i++)
if(!able[i])
ans++;
printf("%d\n",ans);
return 0;
}
9、分巧克力
題意
兒童節那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友們。小明一共有N塊巧克力,其中第i塊是Hi x Wi的方格組成的長方形。為了公平起見,小明需要從這 N 塊巧克力中切出K塊巧克力分給小朋友們。切出的巧克力需要滿足:1. 形狀是正方形,邊長是整數 2. 大小相同 。例如一塊6x5的巧克力可以切出6塊2x2的巧克力或者2塊3x3的巧克力。當然小朋友們都希望得到的巧克力儘可能大,你能幫小Hi計算出最大的邊長是多少麼?
輸入
第一行包含兩個整數N和K。(1 <= N, K <= 100000)
以下N行每行包含兩個整數Hi和Wi。(1 <= Hi, Wi <= 100000)
輸入保證每位小朋友至少能獲得一塊1x1的巧克力。
輸出
輸出切出的正方形巧克力最大可能的邊長。
樣例輸入:
2 10
6 5
5 6
樣例輸出:
2
資源約定:
峰值記憶體消耗(含虛擬機器) < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
注意:
main函式需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要呼叫依賴於編譯環境或作業系統的特殊函式。
所有依賴的函式必須明確地在原始檔中 #include <xxx>
不能通過工程設定而省略常用標頭檔案。
提交程式時,注意選擇所期望的語言型別和編譯器型別。
思路
二分查詢滿足條件的最大邊長。
C++程式
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100005;
int n,k;
ll c[N][2];//c[i][0]、c[i][1]分別表示第i塊巧克力的長和寬
ll cal(int k)//將n塊巧克力分割成長度為k的正方形的總數
{
ll sum=0;
for(int i=0;i<n;i++)
sum+=(c[i][0]/k)*(c[i][1]/k);
return sum;
}
int main()
{
scanf("%d%d",&n,&k);
ll l=1,r=0;//r表示最大的邊長
for(int i=0;i<n;i++)
{
scanf("%lld%lld",&c[i][0],&c[i][1]);
r=max(r,c[i][0]);
r=max(r,c[i][1]);
}
//二分查詢
while(l<=r)
{
int mid=(l+r)>>1;
if(cal(mid)<k)//如果分割的總數小於k
r=mid-1;
else//否則
l=mid+1;
}
printf("%lld\n",l-1);//l表示不能滿足條件的最小邊長,l-1表示滿足條件的最大邊長
return 0;
}
10、油漆面積
題意
X星球的一批考古機器人正在一片廢墟上考古。該區域的地面堅硬如石、平整如鏡。管理人員為方便,建立了標準的直角座標系。每個機器人都各有特長、身懷絕技。它們感興趣的內容也不相同。經過各種測量,每個機器人都會報告一個或多個矩形區域,作為優先考古的區域。矩形的表示格式為(x1,y1,x2,y2),代表矩形的兩個對角點座標。為了醒目,總部要求對所有機器人選中的矩形區域塗黃色油漆。小明並不需要當油漆工,只是他需要計算一下,一共要耗費多少油漆。其實這也不難,只要算出所有矩形覆蓋的區域一共有多大面積就可以了。注意,各個矩形間可能重疊。本題的輸入為若干矩形,要求輸出其覆蓋的總面積。
輸入格式:
第一行,一個整數n,表示有多少個矩形(1<=n<10000)
接下來的n行,每行有4個整數x1 y1 x2 y2,空格分開,表示矩形的兩個對角頂點座標。
(0<= x1,y1,x2,y2 <=10000)
輸出格式:
一行一個整數,表示矩形覆蓋的總面積。
例如,
輸入:
3
1 5 10 10
3 1 20 20
2 7 15 17
程式應該輸出:
340
再例如,
輸入:
3
5 2 10 6
2 7 12 10
8 1 15 15
程式應該輸出:
128
資源約定:
峰值記憶體消耗(含虛擬機器) < 256M
CPU消耗 < 2000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。
注意:
main函式需要返回0;
只使用ANSI C/ANSI C++ 標準;
不要呼叫依賴於編譯環境或作業系統的特殊函式。
所有依賴的函式必須明確地在原始檔中 #include <xxx>
不能通過工程設定而省略常用標頭檔案。
提交程式時,注意選擇所期望的語言型別和編譯器型別。
思路
由於資料規模不大,因此可以用陣列表示地圖,對地圖進行染色就行,如果資料規模較大還是要用線段樹+掃描線做法
注意:聽說測試資料有問題,當結果為8458輸出要改為3796才能AC。
C++程式
使用陣列模擬:
#include<iostream>
using namespace std;
const int N=10002;
bool vis[N][N];
int main()
{
int n,x1,y1,x2,y2;
scanf("%d",&n);
long long ans=0;
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1>x2) swap(x1,x2);
if(y1>y2) swap(y1,y2);
for(int j=x1;j<x2;j++)
for(int k=y1;k<y2;k++)
if(!vis[j][k])
{
ans++;
vis[j][k]=true;
}
}
if(ans==8458) ans=3796;
printf("%lld\n",ans);
return 0;
}
相關文章
- 藍橋杯__省賽__第七屆__C/C++__大學A組C++
- 藍橋杯__省賽__第九屆__C/C++__大學A組C++
- 第十五屆藍橋杯大賽軟體賽省賽 C/C++ 大學 A 組C++
- 2017第八屆藍橋杯C/C++ B組省賽第二題 秒解C++
- 第十三屆藍橋杯省賽A組
- 第十三屆藍橋杯省賽C/C++ B組C++
- 2015年藍橋杯六屆省賽大學B組真題
- 【藍橋杯考前突擊】第十屆藍橋杯省賽C/C++大學B組 試題 D 數的分解C++
- 第十五屆藍橋杯C++B組省賽總結C++
- 第十屆藍橋杯省賽C++B組 等差數列C++
- 第六屆藍橋杯省賽CC++B組C++
- 歷屆藍橋杯省賽(C、C++)的答案(轉)C++
- 第十五屆藍橋杯軟體賽省賽C/C++B 組題解C++
- 第九屆藍橋杯省賽C++A組 倍數問題(dfs)C++
- 2017省賽藍橋杯B組
- 2018藍橋杯省賽B組
- 第九屆藍橋杯B組省賽———乘積最大
- 試題B:小球反彈(第十五屆藍橋杯省賽B組c/c++組)C++
- 2013第四屆藍橋杯省賽C++A組【第一題:高斯日記】C++
- 第十一屆藍橋杯省賽CC++組第二場比賽C++
- 方格分割 二進位制列舉+DFS(2017 第八屆藍橋杯省賽A組 第4題)
- 2013年第四屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 2014年第五屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 第十四屆藍橋杯省賽C++ B組(個人經歷 + 題解)C++
- 第14屆藍橋杯B組國賽
- 2018第九屆藍橋杯省賽C++B組【第四題:測試次數】C++
- 2013第四屆藍橋杯省賽C++B組【第六題:三部排序】C++排序
- 2016年藍橋杯C/C++組省賽第三題--湊算式C++
- 2016年藍橋杯C/C++組省賽第四題--快速排序C++排序
- 藍橋杯第五屆省賽題目及題解
- 第十四屆藍橋杯大賽軟體賽省賽Python 《三國遊戲》Python遊戲
- 2016年省賽第七屆藍橋杯B組C/C++第九題解 交換瓶子C++
- 2019年省賽第十屆藍橋杯B組C/C++試題H解 等差數列C++
- 2020藍橋杯省賽B組C++(第二場)真題C++
- 2016年藍橋杯C/C++組省賽第一題--煤球數目C++
- 2016年藍橋杯C/C++組省賽第二題--生日蠟燭C++
- 第九屆藍橋杯軟體類省賽 Java B組 題目及解析Java
- 2018年第九屆藍橋杯省賽試題及詳解(Java本科A組)Java