0
点赞
收藏
分享

微信扫一扫

搜索(一部分真题)

古得曼_63b6 2022-03-12 阅读 55

作物杂交

题目描述

作物杂交是作物栽培中重要的一步。已知有 N 种作物 (编号 1 至 N ),第 i 种作物从播种到成熟的时间为 Ti​。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。

初始时,拥有其中 M 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到

如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,A × C → D。则最短的杂交过程为:

第 1 天到第 7 天 (作物 B 的时间),A × B → C。

第 8 天到第 12 天 (作物 A 的时间),A × C → D。

花费 12 天得到作物 D 的种子。

输入描述

输入的第 1 行包含 4 个整数 N,M,K,T,N 表示作物种类总数 (编号 1 至 N),M 表示初始拥有的作物种子类型数量,K 表示可以杂交的方案数,T 表示目标种子的编号。

第 2 行包含 N 个整数,其中第 i 个整数表示第 i 种作物的种植时间 Ti​ (1≤Ti​≤100)。

第 3 行包含 M 个整数,分别表示已拥有的种子类型Kj​ (1≤Kj​≤M),Kj​ 两两不同。

第 4 至 K + 3 行,每行包含 3 个整数 A,B,C,表示第 A 类作物和第 B 类作物杂交可以获得第 C 类作物的种子。

其中,1≤N≤2000,2≤M≤N,1≤K≤10^5,1≤T≤N, 保证目标种子一定可以通过杂交得到。

输出描述

输出一个整数,表示得到目标种子的最短杂交时间。

6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6
16

第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。

第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的作物种子。

第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。

第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。

总共花费 16 天。

#include<iostream>
using namespace std;

//作物杂交
int N,M,K,T;//作物类型总数,拥有类型数,可杂交方案,种子编号
int t[2002];//杂交所需时间
bool have[2002];//已获得的种子
struct father{//杂交植物的双亲记录
    int num;
    int u[2002];
    int v[2002];
    int limtime;
}fa[2002];
bool dfs(int x){
  if(fa[x].num==0) return false;//无法通过杂交获得
  for(int i=1;i<=fa[x].num;i++){//遍历x的杂交双亲,获取最小的时间
    int u=fa[x].u[i];
    int v=fa[x].v[i];
    if(!have[u]){
      if(!dfs(u))  continue;
    }
    if(!have[v]){
      if(!dfs(v)) continue;
    }
    if(!fa[x].limtime)//得到c,只有一种杂交方案
      fa[x].limtime=max(fa[u].limtime,fa[v].limtime)+max(t[u],t[v]);//初始化:父母两方中比较大的一边的杂交时间,再加上父母中大的生长时间
    else//得到c,有多种杂交方案,取时间最小的
      fa[x].limtime=min(fa[x].limtime, max(fa[u].limtime, fa[v].limtime) + max(t[u], t[v]));//取最小值
  }   
  have[x] = true;//x设置为可获得
  return true; 
  }
int main()
{
  cin>>N>>M>>K>>T;
  for(int i=1;i<=N;i++){
    cin>>t[i];
  }
  for(int i=1;i<=M;i++){
    int tmp;
    cin>>tmp;
    have[tmp]=true;
  }
  for(int i=1;i<=K;i++){
    int a,b,c;
    cin>>a>>b>>c;
    int tem=++fa[c].num;//能通过杂交得到c的方案数
    if(t[a]<t[b]) swap(a,b);//保证u数组是较大的一边
    fa[c].u[tem]=a;
    fa[c].v[tem]=b;
  }
  dfs(T);
  cout<<fa[T].limtime;
  return 0;
}

受伤的皇后

题目描述

有一个 n×n 的国际象棋棋盘(n 行 n 列的方格图),请在棋盘中摆放 n 个受伤的国际象棋皇后,要求:

  1. 任何两个皇后不在同一行。
  2. 任何两个皇后不在同一列。
  3. 如果两个皇后在同一条 45 度角的斜线上,这两个皇后之间行号的差值至少为 3 。

请问一共有多少种摆放方案。

输入描述

输入的第一行包含一个整数 n。

其中,1≤n≤10。

输出描述

输出一个整数,表示答案。

4
2
#include<iostream>
using namespace std;

//受伤的皇后
#include<algorithm>
int n,ans,a[10]={0};//n*n的棋盘
bool check(int r,int c){//判断r行c列是否可用
  for(int i=1;i<r;i++){//判断前r-1行中有无与c列冲突的列
    if(a[i]==c) return false;//存在第c列不可以
    if((a[i]+i==r+c)&&(r-i)<3) return false;//对角线上(行和列和相同)
    if((r-i==c-a[i])&&(r-i)<3) return false;//斜对角线(行列差值相同)
  }
  return true;
}
void dfs(int r){
    if(r==n+1){//前r行排完,答案+1
      ans++;
      return ;
    }
    for(int i=1;i<=n;i++){//依次判断1到n列有无可用
      if(check(r,i)){//r行i列可用
        a[r]=i;
        dfs(r+1);
        a[r]=0;//重置便于尝试新方案
      }
    } 
}
int main()
{
    cin>>n;
    dfs(1);
    cout<<ans<<endl;
    return 0;
}

全球变暖

题目描述

你有一张某海域 NxN 像素的照片,"."表示海洋、"#"表示陆地,如下所示:

.......

.##....

.##....

....##.

..####.

...###.

.......

其中"上下左右"四个方向上连在一起的一片(如图中紫色的一片和橙色的一片为两个岛屿)陆地组成一座岛屿。例如上图就有 2 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。(只有红色的不会被淹没

例如上图中的海域未来会变成如下样子:

.......

.......

.......

.......

....#..

.......

.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没

输入描述

第一行包含一个整数 N (1≤N≤1000)。

以下 N 行 N 列代表一张海域照片。

照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。

输出一个整数表示答案。

7
.......
.##....
.##....
....##.
..####.
...###.
.......
1

岛屿中一个满足四周都是‘#’就不会被淹,剩下的即为所求。

#include <iostream>
using namespace std; 

//全球变暖
const int N=1005;
char mp[N][N];//海域图
int vis[N][N];
bool flag;//flag==0:表示岛屿被淹没,==1:表示未被淹没
int dirc[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//方向
void dfs(int i,int j,int vis[N][N]){
    if(mp[i-1][j]=='#'&&mp[i+1][j]=='#'&&mp[i][j-1]=='#'&&mp[i][j+1]=='#')//四个方向都是陆地,则该点不会被淹没
        flag=1;
    for(int k=0;k<4;k++){//四个方向
        if(mp[i+dirc[k][0]][j+dirc[k][1]]=='#'&&vis[i+dirc[k][0]][j+dirc[k][1]]==0){
            vis[i+dirc[k][0]][j+dirc[k][1]]=1;
            dfs(i+dirc[k][0],j+dirc[k][1],vis);
        }
    }
}
int main()
{
    int n,ans=0;
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>mp[i][j];
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(mp[i][j]=='#'&&vis[i][j]==0){
                flag=0;//初始化
                vis[i][j]=0;
                dfs(i,j,vis);
                if(flag==0)
                  ans++;
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

小朋友崇拜圈

题目描述

班里 N 个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。

在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边

求满足条件的圈最大多少人

小朋友编号为 1,2,3,⋯N。

输入描述

输入第一行,一个整数 N(3<N<10^5)。

接下来一行 N 个整数,由空格分开

输出描述

要求输出一个整数,表示满足条件的最大圈的人数。

9
3 4 2 5 3 8 4 6 9
4

如下图所示,崇拜关系用箭头表示,红色表示不在圈中。

显然,最大圈是[2 4 5 3] 构成的圈。

#include<iostream>
using namespace std;

//小朋友崇拜圈
#include<cstring>
int main()
{
    int n;
    cin>>n;
    int a[n+1],vis[n+1];//a下标表示第i个小朋友,值表示其崇拜的小朋友编号
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int cnt,maxn=0,j;
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof(vis));
        cnt=0;
        if(vis[i]==0){
            for(j=i;vis[j]==0;j=a[j]){//让被崇拜的小朋友变成下一个目标
                vis[j]=1;//标记为1
                cnt++;//长度+1
            }
            if(a[j]!=a[i]) cnt=0;//如果最后一个小朋友崇拜的人不是"第一个",则不是环
            maxn=max(maxn,cnt);
        }
    }
    cout<<maxn<<endl;
    return 0;
}

跳蚱蜢(bfs)

题目描述

如下图所示: 有 9 只盘子,排成 1 个圆圈。 其中 8 只盘子内装着 8 只蚱蜢,有一个是空盘。 我们把这些蚱蜢顺时针编号为 1 ~ 8。

每只蚱蜢都可以跳到相邻的空盘中, 也可以再用点力,越过一个相邻的蚱蜢跳到空盘中

请你计算一下,如果要使得蚱蜢们的队形改为按照逆时针排列, 并且保持空盘的位置不变(也就是 1−8 换位,2−7换位,...),至少要经过多少次跳跃

正则问题

题目描述

考虑一种简单的正则表达式:

只由 x ( ) | 组成的正则表达式。

小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是 6。

输入描述

一个由 x()| 组成的正则表达式。输入长度不超过 100,保证合法。

输出描述

这个正则表达式能接受的最长字符串的长度。

((xx|xxx)x|(x|xx))xx

6

(1)先看第一个括号,发现里面还有嵌套括号,找到最内部的括号,括号内是一个或操作。((xx|xxx)x|(x|xx))xx,得:(xxxx|(x|xx))xx

(2)继续执行最内部括号。(xxxx|(x|xx))xx,得:(xxxx|xx)xx

(3)继续执行最后括号。(xxxx|xx)xx,得:xxxxxx,结束,得长度为6的字符串。

括号优先级最高,其次是 |(或)括号内是一个整体,从最里面的括号开始算,取 | 两边最长的保留

#include <iostream>
using namespace std; 

//正则问题
string str;
int pos=0;
int dfs(){
  int ans=0,tmp=0;
  while(pos<str.length()){
    if(str[pos]=='('){//遇到左括号,继续递归(相当于进栈),直到最后一层括号
      pos++;
      tmp+=dfs();
    }else if(str[pos]==')'){//遇到右括号,递归返回,相当于出栈
      pos++;
      break;
    }else if(str[pos]=='x'){//遇到x直接计数
      tmp++;
      pos++;
    }else{//遇到|,取最大值
      pos++;
      ans=max(ans,tmp); 
      tmp=0;
    }
  }
  ans=max(ans,tmp);
  return ans;
}
int main()
{
    cin>>str;
    cout<<dfs()<<endl;
    return 0;
}
举报

相关推荐

0 条评论