作物杂交
题目描述
作物杂交是作物栽培中重要的一步。已知有 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 个受伤的国际象棋皇后,要求:
- 任何两个皇后不在同一行。
- 任何两个皇后不在同一列。
- 如果两个皇后在同一条 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;
}