2.23日浙江科技学院天梯热身赛

1-1Hello World! (5 分)

本题要求编写程序,输出一个短句“Hello World!”。

输入格式:

本题目没有输入。

输出格式:

在一行中输出短句“Hello World!”。

Hello World相信大家都不会陌生,因为大多数人在学习编程的时候在控制台上输出的第一句话就是Hello World。

AC代码

#include
​
using namespace std;
​
 int main()
{
​
 printf("Hello World!");
​
 return 0;
​
 }

 

 

 

 1-2 打印沙漏 (20 分)

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****

 ***

  *

 ***

*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****

 ***

  *

 ***

*****

2

 

用字符打印出一个特定的形状是比较简单的,这道题可能卡死的地方可能是不能第一时间找到方法,判别需要输出的沙漏的层数。

根据题目描述沙漏从中间向两边承等差数列递增,数量分别为1 3 5 7 ,因此不难发现组成沙漏的字符总数num和沙漏的层数ans的关系

 

AC代码

 

#include 
​
using namespace std;
​
int main()
{
​
int a;
​
char b;
​
scanf("%d %c",&a,&b);
​
int num=1,ans=0,i=1;
​
//num记录最大的沙漏所能容纳的数量,ans记录层数
​
while(num<=a)
​
{
​
i+=2;
​
num+=i*2;
​
ans++;
​
}
​
num-=i*2;
​
int c=a-num;
​
//打印上半部分
​
for(int j=ans;j>=1;j--)
​
{
​
int k=j*2-1;
​
​
​
int z=(ans*2-1-k)/2;
​
while(z>0)
​
{
​
printf(" ");
​
z--;
​
}
​
while(k>0)
​
{
​
printf("%c",b);
​
k--;
​
}
​
printf("\n");
​
}
​
//打印下半部分
​
for(int j=ans;j>1;j--)
​
{
​
int k=(j-2);
​
int z=ans*2-k*2-1;
​
while(k>0)
​
{
​
printf(" ");
​
k--;
​
}
​
while(z>0)
​
{
​
printf("%c",b);
​
z--;
​
}
​
printf("\n");
​
}
​
printf("%d",c);
​
//输出剩余数量
​
//printf("\n\n\n\n\n\n");
​
//}
​
//
​
return 0;
​
}

 

1-3 计算摄氏温度 (5 分)

给定一个华氏温度F,本题要求编写程序,计算对应的摄氏温度C。计算公式:C=5×(F−32)/9。题目保证输入与输出均在整型范围内。

输入格式:

输入在一行中给出一个华氏温度。

输出格式:

在一行中按照格式“Celsius = C”输出对应的摄氏温度C的整数值。

输入样例:

150

输出样例:

Celsius = 65

按照题目表示输出就可以,没有什么坑点

AC代码

#include
​
using namespace std;
​
 int main()
{
​
 int a,b;
​
 cin>>a;
​
 b=5*(a-32)/9;
​
 printf("Celsius = %d\n",b);
​
 return 0;
​
 }

 

 

 1-04 考试座位号 (15 分)

每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位。正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试座位就座。但有些考生迟到了,试机已经结束,他们只能拿着领到的试机座位号码求助于你,从后台查出他们的考试座位号码。

输入格式:

输入第一行给出一个正整数 N(≤1000),随后 N 行,每行给出一个考生的信息:准考证号 试机座位号 考试座位号。其中准考证号由 16 位数字组成,座位从 1 到 N 编号。输入保证每个人的准考证号都不同,并且任何时候都不会把两个人分配到同一个座位上。

考生信息之后,给出一个正整数 M(≤N),随后一行中给出 M 个待查询的试机座位号码,以空格分隔。

输出格式:

对应每个需要查询的试机座位号码,在一行中输出对应考生的准考证号和考试座位号码,中间用 1 个空格分隔。

输入样例:

4

3310120150912233 2 4

3310120150912119 4 1

3310120150912126 1 3

3310120150912002 3 2

2

3 4

输出样例:

3310120150912002 2

3310120150912119 1

定义一个结构体,存储准考证号,试机座位号,考试座位号。然后按照题目要求查询并输出

AC代码

 

#include
​
using namespace std;
​
//#define N 1000000000000000010
​
struct node
​
{
​
char zkz[20];
​
int a,b;
​
};
​
//long long a[N];
​
int main()
{
​
int n;
​
struct node std[1005];
​
cin>>n;
​
for(int i=1;i<=n;i++)
​
cin>>std[i].zkz>>std[i].a>>std[i].b;
​
int m;
​
cin>>m;
​
while(m--)
​
{
​
int num;
​
cin>>num;
​
for(int i=1;i<=n;i++)
​
{
​
if(std[i].a==num)
​
printf("%s %d\n",std[i].zkz,std[i].b);
​
}
​
}
​
return 0;
​
}
​​

1-5 连续因子 (20 分)

一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3×5×6×7,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。

输入格式:

输入在一行中给出一个正整数 N(1<N<231)。

输出格式:

首先在第 1 行输出最长连续因子的个数;然后在第 2 行中按 因子1*因子2*……*因子k 的格式输出最小的连续因子序列,其中因子按递增顺序输出,1 不算在内。

输入样例:

630

输出样例:

3

5*6*7

 

并没有什么特殊的方法直接暴力即可

1.此题目的原型类似于找素数,利用嵌套的循环来解决。

2.为了防止超时,又因为除了所有素数,至少会有两个数相乘,所以将循环控制在sqrt()中;

3.因为有记录长度的变量,可以利用此变量来将特殊情况(即所有素数)表示,即如果长度为1,那么

   就输出长度1和数本身;

 

 

AC代码

 

#include 
​
#include
​
using namespace std;
​
int yin[13];
​
void show(int n,int yin[]){
​
cout<>shu;
​
 
​
for(int i=2;i<=sqrt(shu);i++){
​
int ge=0;
​
int myin[13];
​
long long int a=shu;
​
for(int j=i;(!(a%j))&&a;j++)
​
{
​
myin[ge]=j;
​
ge++;
​
if(ge>mge){
​
mge=ge;
​
for(int k=0;k

1-6 念数字 (10 分)

输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu字。十个数字对应的拼音如下:

0: ling

1: yi

2: er

3: san

4: si

5: wu

6: liu

7: qi

8: ba

9: jiu

输入格式:

输入在一行中给出一个整数,如:1234。

提示:整数包括负数、零和正数。

输出格式:

在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如 yi er san si。

输入样例:

-600

输出样例:

fu liu ling ling

这是一个分解整数的题目,普通的分解整数一般情况下是对输入的数对10取余,但是并不适合本道题,只要把输入的数当成字符串来看就好了,不同的字符输出不同的读音

AC代码

#include
​
using namespace std;
​
 
​
int main()
{
​
char a[15][5]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
​
char b[100];
​
cin>>b;
​
if(b[0]=='-')
​
printf("fu");
​
else
​
printf("%s",a[b[0]-'0']);
​
for(int i=1;i

1-7求整数段和 (10 分)

给定两个整数AB,输出从AB的所有整数以及这些数的和。

输入格式:

输入在一行中给出2个整数AB,其中−100≤AB≤100,其间以空格分隔。

输出格式:

首先顺序输出从AB的所有整数,每5个数字占一行,每个数字占5个字符宽度,向右对齐。最后在一行中按Sum = X的格式输出全部数字的和X。

输入样例:

-3 8

输出样例:

   -3   -2   -1    0    1

    2    3    4    5    6

    7    8

Sum = 30

简单题,用一个循环,循环输出从A到B的所有数。并用一个边量记录数字的和。最后打印输出即可

AC代码

#include
​
using namespace std;
​
//#define N 1000000000000000010
​
/*struct node
​
{
​
char zkz[20];
​
int a,b;
​
};*/
​
//long long a[N];
​
int main()
{
​
int a,b;
​
cin>>a>>b;
​
int sum=0;
​
int num=0;
​
for(int i=a;i<=b;i++)
​
{
​
printf("%5d",i);
​
num++;
​
if(num%5==0)
​
printf("\n");
​
sum+=i;
​
}
​
if((b-a+1)%5!=0)
​
printf("\n");
​
printf("Sum = %d\n",sum);
​
return 0;
​
}
 

1-8 个位数统计 (15 分)

给定一个 k 位整数 N=dk−110k−1+⋯+d1101+d0 (0≤di≤9, i=0,⋯,k−1, dk−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311,则有 2 个 0,3 个 1,和 1 个 3。

输入格式:

每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N

输出格式:

对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

输入样例:

100311

输出样例:

0:2

1:3

3:1

 

题目要求我们记录并按升序输出各个数字出现的次数

用桶排序记录,然后按照桶下表从小到大输出。

AC代码

#include
​
using namespace std;
​
int main()
{
​
char ch[1005];
​
int a[10];
​
//memset(a,0,10);
​
for(int i=0;i<=9;i++)
​
//printf("%d\n",a[i]);
​
a[i]=0;
​
cin>>ch;
​
for(int i=0;i

 

 

2-1 城市间紧急救援 (25 分)

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数NMSD,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从SD的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3

20 30 40 10

0 1 1

1 3 2

0 3 3

0 2 2

2 3 2

输出样例:

2 60

0 1 3

一道典型的最短路径问题,首先想到使用迪杰斯特拉算法,进行最短路i经的求解,但是当我们深入分析时却发现,自己没有办法统计最短路径的条数和能够召集的最多的救援队数量,我们只能统计最短路径的边权值,要考虑最优路径上的点权和尽可能大,所以出现两路径长度相等时要进行关于点权和的判断。另外还要记录最短路径的条数,只需开一个数组记载,每次更新时基于上一点的最短路径条数更新即可。每次更新最优路径时,将上一点记录在theway数组,用于最后输出最优路径。

AC代码

#include
#include
#include
#include
 
using namespace std;
 
struct node {
  int v, len;
  node(int _v, int _len) {
    v = _v;
    len = _len;
  }
};
 
int N, M, S, D, INF = 1000000000;
int teams[500], d[500], countInq[500];
vector graph[500];
bool inq[500];
set pre[500];
vector tempPath, path;
int count = 0, maxTeams = 0;
 
bool spfa(int s);
void dfs(int nowVisit);
 
int main() {
  std::ios::sync_with_stdio(false);
  cin >> N >> M >> S >> D;
  for(int i = 0; i < N; i++) {
    cin >> teams[i];
  }
  for(int i = 0; i < M; i++) {
    int v1, v2, len;
    cin >> v1 >> v2 >> len;
    graph[v1].push_back(node(v2, len));
    graph[v2].push_back(node(v1, len));
  }
  spfa(S);
  dfs(D);
  cout << count << " " << maxTeams << endl;
  for(int i = path.size() - 1; i >= 0; i--){
    cout << path[i];
    if(i == 0){
      cout << endl; 
    }else{
      cout << " ";
    }
  }
  return 0;
}
 
bool spfa(int s) {
  fill(d, d + N, INF);
  fill(countInq, countInq + N, 0);
  fill(inq, inq + N, false);
  d[s] = 0;
  queue q;
  q.push(s);
  countInq[s]++;
  inq[s] = true;
  while(!q.empty()) {
    int u = q.front();
    q.pop();
    inq[u] = false;
    for(int i = 0; i < graph[u].size(); i++) {
      int v = graph[u][i].v;
      int len = graph[u][i].len;
      if(d[u] + len < d[v]) {
        d[v] = d[u] + len;
        pre[v].clear();
        pre[v].insert(u);
        if(!inq[v]) {
          q.push(v);
          inq[v] = true;
          countInq[v]++;
          if(countInq[v] > N - 1){
            return false;
          }
        }
      }else if(d[u] + len == d[v]) {
        pre[v].insert(u);
        if(!inq[v]) {
          q.push(v);
          inq[v] = true;
          countInq[v]++;
          if(countInq[v] > N - 1){
            return false;
          }
        }
      }
    }
  }
  return true;
}
 
void dfs(int nowVisit) {
  tempPath.push_back(nowVisit);
  if(nowVisit == S){
    count++;
    int tempTeams = 0;
    for(int i = 0; i < tempPath.size(); i++){
      tempTeams += teams[tempPath[i]];
    }
    if(tempTeams > maxTeams){
      maxTeams = tempTeams;
      path = tempPath;
    }
    tempPath.pop_back();
    return; 
  }
  for(set::iterator it = pre[nowVisit].begin(); it != pre[nowVisit].end(); it++){
    dfs(*it);
  }
  tempPath.pop_back();
}
​

2-2 链表去重 (25 分)

给定一个带整数键值的链表 L,你需要把其中绝对值重复的键值结点删掉。即对每个键值 K,只有第一个绝对值等于 K 的结点被保留。同时,所有被删除的结点须被保存在另一个链表上。例如给定 L 为 21→-15→-15→-7→15,你需要输出去重后的链表 21→-15→-7,还有被删除的链表 -15→15。

输入格式:

输入在第一行给出 L 的第一个结点的地址和一个正整数 N(≤105,为结点总数)。一个结点的地址是非负的 5 位整数,空地址 NULL 用 -1 来表示。

随后 N 行,每行按以下格式描述一个结点:

地址 键值 下一个结点

其中地址是该结点的地址,键值是绝对值不超过104的整数,下一个结点是下个结点的地址。

输出格式:

首先输出去重后的链表,然后输出被删除的链表。每个结点占一行,按输入的格式输出。

输入样例:

00100 5
99999 -7 87654
23854 -15 00000
87654 15 -1
00000 -15 99999
00100 21 23854

输出样例:

00100 21 23854
23854 -15 99999
99999 -7 -1
00000 -15 87654
87654 15 -1

思路:模拟,也没什么坑点,具体见代码

 

#define LOCAL
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 3000000
#define inf 40000000
#define LL long long
int vis[20000];//i数字是否出现过 
typedef pair P;
map m;
struct node
{
  int val;
  int now,next;
}ans1[maxn],ans2[maxn];
int main()
{
  #ifdef LOCAL
  //freopen("data.in","r",stdin);
  //freopen("data.out","w",stdout);
  #endif
  int n,b;
  int a,c,s;
  cin>>s>>n;
  for(int i=0;i>a>>b>>c;
    m[a]=make_pair(b,c);
  }
  int t=0,val;
  int last=s;
  int last1=0,last2=0;
  while(t!=n)
  {
    t++;
    map::iterator p=m.find(last);
    val=((*p).second).first;
    int temp=((*p).second).second;
    if(vis[abs(val)])
    {
      if(last2)
      {
        ans2[last2-1].next=last;
      }
      ans2[last2].now=last;
      ans2[last2].val=val;
      ans2[last2].next=-1;
      last2++;
    }
    else 
    {
      vis[abs(val)]=1;
      if(last1)
      {
        ans1[last1-1].next=last;
      }
      ans1[last1].now=last;
      ans1[last1].val=val;
      ans1[last1].next=-1;
      last1++;
    }
    last=temp;
  }
  for(int i=0;i
 

 

2-3 二叉搜索树的结构 (25 分)

二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树。(摘自百度百科)

给定一系列互不相等的整数,将它们顺次插入一棵初始为空的二叉搜索树,然后对结果树的结构进行描述。你需要能判断给定的描述是否正确。例如将{ 2 4 1 3 0 }插入后,得到一棵二叉搜索树,则陈述句如“2是树的根”、“1和4是兄弟结点”、“3和0在同一层上”(指自顶向下的深度相同)、“2是4的双亲结点”、“3是4的左孩子”都是正确的;而“4是2的左孩子”、“1和3是兄弟结点”都是不正确的。

输入格式:

输入在第一行给出一个正整数N(≤100),随后一行给出N个互不相同的整数,数字间以空格分隔,要求将之顺次插入一棵初始为空的二叉搜索树。之后给出一个正整数M(≤100),随后M行,每行给出一句待判断的陈述句。陈述句有以下6种:

  • A is the root,即"A是树的根";

  • A and B are siblings,即"AB是兄弟结点";

  • A is the parent of B,即"AB的双亲结点";

  • A is the left child of B,即"AB的左孩子";

  • A is the right child of B,即"AB的右孩子";

  • A and B are on the same level,即"AB在同一层上"。

题目保证所有给定的整数都在整型范围内。

输出格式:

对每句陈述,如果正确则输出Yes,否则输出No,每句占一行。

输入样例:

5
2 4 1 3 0
8
2 is the root
1 and 4 are siblings
3 and 0 are on the same level
2 is the parent of 4
3 is the left child of 4
1 is the right child of 2
4 and 0 are on the same level
100 is the right child of 3

输出样例:

Yes
Yes
Yes
Yes
Yes
No
No
No

思路:依旧是模拟。。。坑点是应该要用指针实现,还有判断是否在同一层(我被wa了一次,不过记录下在第几层就好了);

代码如下:

#define LOCAL
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 3000000
#define inf 400000000
#define LL long long
int a[200];
struct node
{
  int val;
  node *l,*r,*f;
};
node *root=NULL;
void tinsert(int val)//建树 
{
  if(root==NULL)
  {
    root=(node*)malloc(sizeof(node));
    root->val=val;
    root->l=NULL;
    root->r=NULL;
    root->f=NULL;
    return;    
  }
  else
  {
    node* now=root;
    while(1)
    {
      if(valval)
      {
        if(!now->l)
        {
          now->l=(node *)malloc(sizeof(node));
          now->l->val=val;
          now->l->l=NULL;
          now->l->r=NULL;
          now->l->f=now;
          break;
        }
        else
        now=now->l;
      }
      else
      {
        if(!now->r)
        {
          now->r=(node *)malloc(sizeof(node));
          now->r->val=val;
          now->r->l=NULL;
          now->r->r=NULL;
          now->r->f=now;
          break;
        }
        else
        now=now->r;
      }      
    }
​
  }
​
}
node *find(int k)//找到这个节点的父节点,左子节点,右子节点 
{
  node* now=root;
  while(1)
  {
    if(now)//存在节点 
    {
      if(k==now->val)
        return now;
      else if(k>now->val)
        now=now->r; 
      else
        now=now->l;
    }
    else break;
  }
  return NULL;
}
int main()
{
  #ifdef LOCAL
  //freopen("data.in","r",stdin);
  //freopen("data.out","w",stdout);
  #endif
  int n;cin>>n;
  for(int i=0;i>a[i];tinsert(a[i]);
  }
  int root=a[0];
  int m;
  char temp[1000];
  cin>>m;
  getchar();
  while(m--)
  {
    fgets(temp,100,stdin);
    int t=0;
    for(int i=0;if)||!(pb->f))//如果有一个不存在 
      {
        printf("No\n");
        continue;
      }
      if(pa->f->val==pb->f->val)printf("Yes\n");
      else printf("No\n");
    }
    else if(t==5)
    {
      int a,b;
      char tt[4][100];
      sscanf(temp,"%d%s%s%s%s%d",&a,tt[0],tt[1],tt[2],tt[3],&b);
      node *pa=find(a);
      if(!pa)//如果有一个不存在 
      {
        printf("No\n");
        continue;
      }
      if(((pa->l)&&(pa->l->val==b))||((pa->r)&&(pa->r->val==b)))printf("Yes\n");
      else printf("No\n");
    }
    else if(t==6)
    {
      int a,b;
      char s[5][10];
      sscanf(temp,"%d%s%s%s%s%s%d",&a,s[0],s[1],s[2],s[3],s[4],&b);
      node *pb=find(b);
      if(!pb)//如果有一个不存在 
      {
        printf("No\n");
        continue;
      }
      if(strstr(temp,"left"))
      {
        if(!(pb->l))
        {
          printf("No\n");
          continue;
        }
        if(pb->l->val==a)printf("Yes\n");
        else printf("No\n");
      }
      else
      {
        if(!(pb->r))
        {
          printf("No\n");
          continue;
        }
        if(pb->r->val==a)printf("Yes\n");
        else printf("No\n");
      }
    }
    else
    {
      int a,b;
      char tt[100];
      sscanf(temp,"%d%s%d",&a,tt,&b);
      node *pb=find(b);node *pa=find(a);
      if(!pb||!pa||!(pa->f)||!(pb->f)||!(pa->f->f)||!(pb->f->f))//如果有一个不存在 
      {
        printf("No\n");
        continue;
      }
      if(pa->f->f->val==pb->f->f->val)printf("Yes\n");
      else printf("No\n");
    }
  }
  
  
  
  return 0;
}
​
​

 

 

2-4 集合相似度 (25 分)

给定两个整数集合,它们的相似度定义为:Nc/Nt×100%。其中Nc是两个集合都有的不相等整数的个数,Nt是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。

输入格式:

输入第一行给出一个正整数N(≤50),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(≤104),是集合中元素的个数;然后跟M个[0,109]区间内的整数。

之后一行给出一个正整数K(≤2000),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。

输出格式:

对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。

输入样例:

3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3

输出样例:

50.00%

33.33%

思路:集合的交集和并集。。。用set很简单

代码如下:

 

 

#define LOCAL
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 3000000
#define inf 400000000
#define LL long long
sets[60];
​
int main()
{
  #ifdef LOCAL
  //freopen("data.in","r",stdin);
  //freopen("data.out","w",stdout);
  #endif
  int n;
  cin>>n;
  for(int i=0;i>m;
    for(int j=0;j>t;
      s[i].insert(t);
    }
  }
  int k;cin>>k;
  int a,b;
  for(int i=0;i>a>>b;
    vectorc,c2;
    a--,b--;
    set_union(s[a].begin(),s[a].end(),s[b].begin(),s[b].end(),back_inserter(c));
    set_intersection(s[a].begin(),s[a].end(),s[b].begin(),s[b].end(),back_inserter(c2));
    printf("%.2lf%\n",(double)c2.size()/c.size()*100);
  }
  
  
  
  return 0;
}

3-1 特殊堆栈 (30 分)

堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。

输入格式:

输入的第一行是正整数 N(≤105)。随后 N 行,每行给出一句指令,为以下 3 种之一:

Push key
Pop
PeekMedian

其中 key 是不超过 105 的正整数;Push 表示“入栈”;Pop 表示“出栈”;PeekMedian 表示“取中值”。

输出格式:

对每个 Push 操作,将 key 插入堆栈,无需输出;对每个 Pop 或 PeekMedian 操作,在一行中输出相应的返回值。若操作非法,则对应输出 Invalid

输入样例:

17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop

输出样例:

Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid

思路:把栈中元素放入一个vector,插入删除都可以用O(logn)的速度找到位置,找中值O(1),总的时间复杂度nlogn

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int main()
{
  int n;
  vector v1,v;
  scanf("%d",&n);
  vector::iterator it;
  while(n--)
  {
    char ch[15];
    scanf("%s",ch);
    string s = ch;
    if(s == "Push")
    {
      int temp;
      scanf("%d",&temp);
      v1.push_back(temp);
      it = lower_bound(v.begin(),v.end(),temp);
      v.insert(it,temp);
    }
    else if(s == "Pop")
    {
      if(v1.size() == 0)
        printf("Invalid\n");
      else 
      {
        it = lower_bound(v.begin(),v.end(),v1[v1.size()-1]);
        v.erase(it);
        printf("%d\n",v1[v1.size()-1]);
        v1.pop_back();
      }
    }
    else if(s == "PeekMedian")
    {
      if(v1.size() == 0)
      {
        printf("Invalid\n");
        continue;
      }
      if(v.size() % 2 == 0)
        printf("%d\n",v[v.size()/2-1]);
      else
        printf("%d\n",v[v.size()/2]);
​
    }
​
  }
​
  return 0;
​
}

3-2 社交集群 (30 分)

当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。

输入格式:

输入在第一行给出一个正整数 N(≤1000),为社交网络平台注册的所有用户的人数。于是这些人从 1 到 N 编号。随后 N 行,每行按以下格式给出一个人的兴趣爱好列表:

Ki: hi[1] hi[2] ... hi[Ki]

其中Ki(>0)是兴趣爱好的个数,hi[j]是第j个兴趣爱好的编号,为区间 [1, 1000] 内的整数。

输出格式:

首先在一行中输出不同的社交集群的个数。随后第二行按非增序输出每个集群中的人数。数字间以一个空格分隔,行末不得有多余空格。

输入样例:

8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4

输出样例:

3
4 3 1

思路:把每个人和每个兴趣作为节点,i人如果有t兴趣,i,t就存在一条有向边;如此就得到一个图,接下来就是找这个图的连通块的个数;(并查集和dfs都可以)

ps:dfs我没试过,但是应该可以,有兴趣可以尝试下;

代码如下:

#define LOCAL
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 3000000
#define inf 400000000
#define LL long long
int  G[2000][2000];
int f[2000];//每个人的最终领导者
int cnt[2000]; 
int n;
bool cmp(int a,int b)
{
  return a>b;
}
int find(int x)
{
  if(x==f[x])return x;
  return f[x]=find(f[x]);
}
int main()
{
  #ifdef LOCAL
  //freopen("data.in","r",stdin);
  //freopen("data.out","w",stdout);
  #endif
  cin>>n;
  for(int i=1;i<=n;i++)
  {
    int m,t;
    scanf("%d:",&m);
    for(int j=0;j

3-3 肿瘤诊断 (30 分)

在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环。给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积。

输入格式:

输入第一行给出4个正整数:M、N、L、T,其中M和N是每张切片的尺寸(即每张切片是一个M×N的像素矩阵。最大分辨率是1286×128);L(≤60)是切片的张数;T是一个整数阈值(若疑似肿瘤的连通体体积小于T,则该小块忽略不计)。

最后给出L张切片。每张用一个由0和1组成的M×N的矩阵表示,其中1表示疑似肿瘤的像素,0表示正常像素。由于切片厚度可以认为是一个常数,于是我们只要数连通体中1的个数就可以得到体积了。麻烦的是,可能存在多个肿瘤,这时我们只统计那些体积不小于T的。两个像素被认为是“连通的”,如果它们有一个共同的切面,如下图所示,所有6个红色的像素都与蓝色的像素连通。

2.23日浙江科技学院天梯热身赛_第1张图片

 

输出格式:

在一行中输出肿瘤的总体积。

输入样例:

3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0

输出样例:

26

思路:暴力搜索,不过注意用bfs,dfs会超时两个点

代码如下

#define LOCAL
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 3000000
#define inf 400000000
#define LL long long
int G[100][1300][200];//访问过变成2 
int then[6][3]={{1,0,0},{-1,0,0},{0,-1,0},{0,1,0},{0,0,-1},{0,0,1}};
int m,n,l,t;
struct node
{
  int x,y,z;
  node(int x=0,int y=0,int z=0):z(x),x(y),y(z){}
};
bool judge(int z,int x,int y)
{
  if(x<1||x>m||y<1||y>n||z<1||z>l||G[z][x][y]==0||G[z][x][y]==2)return false;
  return true;
}
queue Q;
int bfs(int z,int x,int y)//返回该块的大小 
{
  G[z][x][y]=2;
  Q.push(node(z,x,y));
  int ans=1;
  while(!Q.empty())
  {
    node now=Q.front();
    Q.pop();
    for(int i=0;i<6;i++)
    {
      int zz=now.z+then[i][0];
      int xx=now.x+then[i][1];
      int yy=now.y+then[i][2];
      if(judge(zz,xx,yy))
      {
        Q.push(node(zz,xx,yy));
        G[zz][xx][yy]=2;
        ans++;
      }
    }
  }
  return ans;
}
int main()
{
  #ifdef LOCAL
  //freopen("data.in","r",stdin);
  //freopen("data.out","w",stdout);
  #endif
  int ans=0;
  cin>>m>>n>>l>>t;
  int now=0;
  for(int k=1;k<=l;k++)
  for(int i=1;i<=m;i++)
  for(int j=1;j<=n;j++)
  {
    scanf("%d",&G[k][i][j]);
  }
  
  for(int k=1;k<=l;k++)
  for(int i=1;i<=m;i++)
  for(int j=1;j<=n;j++)
  {
    if(G[k][i][j]==1)
    {
      int temp=bfs(k,i,j);
      if(temp>=t) ans+=temp;
    } 
  }
  cout<

 

你可能感兴趣的:(基础算法)