您的位置:首页 > 其它

蓝桥杯——历届试题(11-17)

2015-03-15 16:35 141 查看
PREV-11 横向打印二叉树

问题描述:

二叉树可以用于排序。其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。

当遇到空子树时,则把该节点放入那个位置。

比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如下图所示,其中.表示空白。

…|-12

10-|

…|-8-|

…….|…|-7

…….|-5-|

………..|-4

本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横向打印该二叉树。

输入格式:

输入数据为一行空格分开的N个整数。 N<100,每个数字不超过10000。

输入数据中没有重复的数字。

输出格式:

输出该排序二叉树的横向表示。为了便于评卷程序比对空格的数目,请把空格用句点代替:

样例输入1

10 5 20

样例输出1

…|-20

10-|

…|-5

样例输入2

5 10 20 8 4 7

样例输出2

…….|-20

..|-10-|

..|….|-8-|

..|……..|-7

5-|

..|-4

分析:建树插入都不难,输出有点难,按右根左的中序遍历二叉树,每个节点,如果右孩子有左孩子,则右孩子的左子树全部有一个竖线,同理对于左孩子的右子树。用vector记录都哪里有竖线。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define inf 1000000000
int a[40000];
vector<int>sx[40000];
char s[1000];
void f(int t,int pos)
{
if(a[t]!=inf)
{
sx[t].push_back(pos);
f(t*2,pos);
f(t*2+1,pos);
}
}
void dfs(int t,int pos)
{
int numlen=(int)log10(a[t])+1;
if(a[4*t+2]!=inf)f(4*t+2,pos+numlen+1);
if(a[4*t+1]!=inf)f(4*t+1,pos+numlen+1);
if(a[t*2+1]!=inf)dfs(t*2+1,pos+numlen+3);
for(int i=0;i<=pos;i++)s[i]='.';
for(int i=0;i<sx[t].size();i++)s[sx[t][i]]='|';
if(t!=1){s[pos-2]='|';s[pos-1]='-';s[pos]='\0';}
else s[pos]='\0';
cout<<s<<a[t];
if(a[t*2]!=inf||a[t*2+1]!=inf)cout<<"-|";
cout<<endl;
if(a[t*2]!=inf)dfs(t*2,pos+numlen+3);
}
int main()
{
char ch;
for(int i=0;i<40000;i++)a[i]=inf;
int t;
while(scanf("%d",&t)!=EOF)
{
int p=1;
while(a[p]!=inf)
{
if(t<a[p])p=p*2;
else p=p*2+1;
}
a[p]=t;
scanf("%c",&ch);
if(ch!=' ')break;
}
dfs(1,0);
return 0;
}


PREV-12 危险系数

问题描述:

抗日战争时期,冀中平原的地道战曾发挥重要作用。

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数DF(x,y):

对于两个站点x和y (x != y), 如果能找到一个站点z,当z被敌人破坏后,x和y不连通,那么我们称z为关于x,y的关键点。相应的,对于任意一对站点x和y,危险系数DF(x,y)就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式:

输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,通道数;

接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条通道;

最后1行,两个数u,v,代表询问两点之间的危险系数DF(u, v)。

输出格式:

一个整数,如果询问的两点不连通则输出-1.

样例输入

7 6

1 3

2 3

3 4

3 5

4 5

5 6

1 6

样例输出

2

解析:求图上能分割两点的割点数量,思路时去掉某一个点,uv不再联通,判断联通方法很多,深搜广搜都行,这里用的并查集。

也可以进一步优化:比如uv右边就不用搜索了,割点数为0;

比如,一旦中间u和v就联通了,就搜索下一个点。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#in
4000
clude <queue>
using namespace std;
#define inf 1000000000
int n,m;
struct edge
{
int u,v;
};
edge e[2005];
int father[1005];
int findf(int x)
{
if(father[x]==x)return x;
return findf(father[x]);
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v;
e[i].u=u;
e[i].v=v;
}
int u,v;
cin>>u>>v;
int i,sum=0;
for(i=0;i<=n;i++)
{
if(i==u||i==v)continue;
for(int j=1;j<=n;j++)father[j]=j;
for(int j=0;j<m;j++)
{
if(i==e[j].u||i==e[j].v)continue;
int x=findf(e[j].u);
int y=findf(e[j].v);
if(x!=y)father[x]=y;
}
int x=findf(u);
int y=findf(v);
if(i==0&&x!=y)break;
if(x!=y)sum++;
}
if(i==0)cout<<-1<<endl;
else cout<<sum<<endl;
return 0;
}


测试结果:

评测点序号 评测结果 得分 CPU使用 内存使用 下载评测数据

1 正确 20.00 15ms 876.0KB 输入 输出

2 正确 20.00 15ms 876.0KB VIP特权

3 正确 20.00 0ms 876.0KB VIP特权

4 正确 20.00 0ms 876.0KB VIP特权

5 正确 20.00 125ms 876.0KB VIP特权

PREV-13 网络寻路

问题描述:

X 国的一个网络使用若干条线路连接若干个节点。节点间的通信是双向的。某重要数据包,为了安全起见,必须恰好被转发两次到达目的地。该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径。

源地址和目标地址可以相同,但中间节点必须不同。

输入格式:

输入数据的第一行为两个整数N M,分别表示节点个数和连接线路的条数(1<=N<=10000; 0<=M<=100000)。

接下去有M行,每行为两个整数 u 和 v,表示节点u 和 v 联通(1<=u,v<=N , u!=v)。

输入数据保证任意两点最多只有一条边连接,并且没有自己连自己的边,即不存在重边和自环。

输出格式:

输出一个整数,表示满足要求的路径条数。

样例输入1

3 3

1 2

2 3

1 3

样例输出1

6

样例输入2

4 4

1 2

2 3

3 1

1 4

样例输出2

10

解析:就是找4个点的路径数,首尾可以相同,其他不可以相同。

用邻接表就行,深搜控制深度为4。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define inf 1000000000
int n,m,sum;
vector<int>a[10005];
int vis[10005];
void f(int t,int s)
{
if(t==4)
{
sum++;
return;
}
if(t==1)vis[s]=2;
else vis[s]=1;
for(int i=0;i<a[s].size();i++)
{
if(vis[a[s][i]]==0)f(t+1,a[s][i]);
else if(vis[a[s][i]]==2&&t==3)f(t+1,a[s][i]);
}
vis[s]=0;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
sum=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{

f(1,i);
}
cout<<sum<<endl;
return 0;
}


测试结果:

评测点序号 评测结果 得分 CPU使用 内存使用 下载评测数据

1 正确 20.00 0ms 0.996MB 输入 输出

2 正确 20.00 15ms 1.007MB VIP特权

3 正确 20.00 31ms 1.019MB VIP特权

4 正确 20.00 281ms 1.246MB VIP特权

5 正确 20.00 156ms 1.398MB VIP特权

PREV-14 高僧斗法

问题描述:

  古时丧葬活动中经常请高僧做法事。仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛。

  节目大略步骤为:先用粮食(一般是稻米)在地上“画”出若干级台阶(表示N级浮屠)。又有若干小和尚随机地“站”在某个台阶上。最高一级台阶必须站人,其它任意。(如图1所示)

  两位参加游戏的法师分别指挥某个小和尚向上走任意多级的台阶,但会被站在高级台阶上的小和尚阻挡,不能越过。两个小和尚也不能站在同一台阶,也不能向低级台阶移动。

  两法师轮流发出指令,最后所有小和尚必然会都挤在高段台阶,再也不能向上移动。轮到哪个法师指挥时无法继续移动,则游戏结束,该法师认输。

  对于已知的台阶数和小和尚的分布位置,请你计算先发指令的法师该如何决策才能保证胜出。

  

输入格式:

  输入数据为一行用空格分开的N个整数,表示小和尚的位置。台阶序号从1算起,所以最后一个小和尚的位置即是台阶的总数。(N<100, 台阶总数<1000)

输出格式:

  输出为一行用空格分开的两个整数: A B, 表示把A位置的小和尚移动到B位置。若有多个解,输出A值较小的解,若无解则输出-1。

  

样例输入

1 5 9

样例输出

1 4

样例输入

1 5 8 10

样例输出

1 3

解析:nim游戏博弈策略,两个一对算一堆东西。最多的那一堆减少成异或得0。或者前面某堆加到异或得0。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define inf 1000000000

int main()
{
int a[105],b[105];
char ch;
int i=0;
while(scanf("%d%c",&a[i++],&ch))if(ch=='\n')break;
int count1=i;
int count;
if(count1%2)count=count1-1;
else count=count1;
int j;
for(i=0,j=0;i<count;i+=2)b[j++]=a[i+1]-a[i]-1;
int sum=0;
for(i=0;i<j;i++)sum^=b[i];
if(sum==0)cout<<-1<<endl;
else
{
for(i=0;i<j;i++)
{
if((sum^b[i])<b[i])
{
int temp=sum^b[i];
cout<<a[i*2]<<' '<<a[i*2]+b[i]-temp<<endl;
break;
}
else if(2*i+2<count1)
{
if((sum^b[i])<=a[2*i+2]-a[2*i]-2)
{
int temp=sum^b[i];
cout<<a[i*2+1]<<' '<<a[i*2]+temp+1<<endl;
break;
}
}
}
}
return 0;
}


PREV-15 格子刷油漆

问题描述:

  X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。

  你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)

  比如:a d b c e f 就是合格的刷漆顺序。

  c e f d a b 是另一种合适的方案。

  当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。

  

输入格式:

  输入数据为一个正整数(不大于1000)

输出格式:

  输出数据为一个正整数。

  

样例输入

2

样例输出

24

样例输入

3

样例输出

96

样例输入

22

样例输出

359635897

解析:动态规划,令a[i]为从一角出发的方法数,b[i]为从一角出发回到同一列的方法数,有b[i]=2*b[i-1],b[1]=1;

对于a[i]有三种情况:

1.先到同一列那个点,2*a[i-1]

2.最后回到同一列那个点,b[i]

3.从第二列折一下到第一列那个点,4*a[i-2]

初值a[1]=1,a[2]=6(画的)

最后的结果为a[i]*4+2到n-1开始的中间的部分

假设从中间开始则不能直接到同一列,先左后右或者先右后左。

2*(2*b[i-1]2*a[n-i])+2(2*a[i-1]*2*b[n-i])

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define inf 1000000000

int main()
{
long long a[1005],b[1005],m=1000000007;
int n;

af9b
cin>>n;
a[1]=1;a[2]=6;b[1]=1,b[2]=2;
for(int i=3;i<=n;i++)
{
b[i]=(b[i-1]*2)%m;
a[i]=(a[i-1]*2+a[i-2]*4+b[i])%m;
}
long long sum=(4*a
)%m;
for(int i=2;i<=n-1;i++)
{
for(int j=0;j<8;j++)
{
sum+=(a[n-i]*b[i-1])%m;
sum%=m;
}
for(int j=0;j<8;j++)
{
sum+=(a[i-1]*b[n-i])%m;
sum%=m;
}
}
cout<<sum<<endl;
return 0;
}


PREV-17 约数倍数选卡片

问题描述:

  闲暇时,福尔摩斯和华生玩一个游戏:

  在N张卡片上写有N个整数。两人轮流拿走一张卡片。要求下一个人拿的数字一定是前一个人拿的数字的约数或倍数。例如,某次福尔摩斯拿走的卡片上写着数字“6”,则接下来华生可以拿的数字包括:

  1,2,3, 6,12,18,24 ….

  当轮到某一方拿卡片时,没有满足要求的卡片可选,则该方为输方。

  请你利用计算机的优势计算一下,在已知所有卡片上的数字和可选哪些数字的条件下,怎样选择才能保证必胜!

  当选多个数字都可以必胜时,输出其中最小的数字。如果无论如何都会输,则输出-1。

输入格式:

  输入数据为2行。第一行是若干空格分开的整数(每个整数介于1~100间),表示当前剩余的所有卡片。

  第二行也是若干空格分开的整数,表示可以选的数字。当然,第二行的数字必须完全包含在第一行的数字中。

输出格式:

  程序则输出必胜的招法!!

样例输入

2 3 6

3 6

样例输出

3

样例输入

1 2 2 3 3 4 5

3 4 5

样例输出

4

解析:只做到60分,剩下两个超时,思路时深搜查找,如果孩子里有可以取的则不能取,反之则可以取,推到根节点看能不能取。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
int a[10005],b[10005];
int n,m;
vector<int>p[10005];
bool vis[10005]={0};
int f(int t)
{
for(int i=0;i<n;i++)if(a[i]==t)return i;
}
bool dfs(int t)
{
vis[t]=true;
for(int i=0;i<p[t].size();i++)
{
if(!vis[p[t][i]])
{
bool temp=dfs(p[t][i]);
if(temp==true)
{
vis[t]=false;
return false;
}
}
}
vis[t]=false;
return true;
}
int main()
{
int i=0;
int t;
char ch;
while(scanf("%d%c",&t,&ch))
{
a[i]=t;
for(int j=0;j<i;j++)
{
if(a[i]%a[j]==0||a[j]%a[i]==0)
{
p[i].push_back(j);
p[j].push_back(i);
}
}
i++;
if(ch=='\n')break;
}
n=i;
i=0;
while(scanf("%d%c",&t,&ch))
{
b[i++]=t;
if(ch=='\n')break;
}
m=i;
for(i=0;i<m;i++)
{
if(dfs(f(b[i]))==true)
{
cout<<b[i]<<endl;
break;
}
}
if(i==m)cout<<-1<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: