P1160 队列安排
一个学校里老师要将班上NN个同学排成一列,同学被编号为1\sim N1∼N,他采取如下的方法:
先将11号同学安排进队列,这时队列中只有他一个人;
2-N2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1\sim (i -1)1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;
从队列中去掉M(M<N)M(M<N)个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
#include <bits/stdc++.h>
struct node{
int n;
node *left,*right;
node(int t){
left=right=NULL;
n=t;
}
}*p[100010],*q;
int main(){
int m,n,i,j,k,u=1,v;
p[1]=new node(1);
scanf("%d",&n);
for(i=2;i<=n;i++){
scanf("%d%d",&j,&k);
p[i]=new node(i);
if(k){
if(p[j]->right){
p[j]->right->left=p[i];
p[i]->right=p[j]->right;
}
p[j]->right=p[i];
p[i]->left=p[j];
}
else{
if(p[j]->left){
p[j]->left->right=p[i];
p[i]->left=p[j]->left;
}
p[j]->left=p[i];
p[i]->right=p[j];
if(j==u)u=i;
}
}
scanf("%d",&m);
for(i=1;i<=m;i++){
scanf("%d",&k);
if(p[k]->left)
p[k]->left->right=p[k]->right;
if(p[k]->right){
p[k]->right->left=p[k]->left;
if(k==u)
u=p[k]->right->n;
}
p[k]->left=p[k]->right=NULL;
}
q=p[u];
while(q){
printf("%d ",q->n);
q=q->right;
}
return 0;
}
难得碰到一个链表的题,正好试试手,练一下数据结构的知识。
P1122 最大子树和
小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题。于是当日课后,小明就向老师提出了这个问题:
一株奇怪的花卉,上面共连有NN朵花,共有N-1N−1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的。每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的,说明这朵花看着都让人恶心。所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。老师的任务就是:通过一系列“修剪”(也可以什么“修剪”都不进行),使剩下的那株(那朵)花卉上所有花朵的“美丽指数”之和最大。
老师想了一会儿,给出了正解。小明见问题被轻易攻破,相当不爽,于是又拿来问你。
#include <bits/stdc++.h>
using namespace std;
bool f[16002][16002]={false};
int w[16002][2]={0},i,a,b,o=0,n;
int sum(int a){
int j;
if(w[a][2]==0){
if(w[a][1]<0)return 0;
else return w[a][1];
}
for(j=3;j<=n+2;j++)if(f[a][j]){
f[a][j]=false;f[j-2][a+2]=false;
w[a][1]=w[a][1]+sum(j-2);
if(w[a][1]>o)o=w[a][1];
}
if(w[a][1]<0)return 0;
else return w[a][1];
}
int main ()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&w[i][1]);
}
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&a,&b);
w[a][2]++;
w[b][2]++;
f[b][a+2]=true;
f[a][b+2]=true;
}
sum(1);
printf("%d",o);
return 0;
}
子树问题,还是数据结构的知识,W[1][1]是第一个点的值,W[1][2]是和这个点连接的数量,后面是记录和这个点连接的点。
f数组是记录两个点是否连接。f[x][y]是x点是否能到y点,如果x能到y点那么y点也能到x点,所以f[y][x]也是打开的。
然后就开始深搜。深搜的时候要记得把f关闭,不然会死循环!!!而且双向路都要关闭!!!
搜到最底下就把这个点的值递回来,然后加上沿路所有点的值。
P1140 相似基因
大家都知道,基因可以看作一个碱基对序列。它包含了44种核苷酸,简记作A,C,G,TA,C,G,T。生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物。
在一个人类基因工作组的任务中,生物学家研究的是:两个基因的相似程度。因为这个研究对疾病的治疗有着非同寻常的作用。
#include<bits/stdc++.h>
using namespace std;
int la,lb,a[110],b[110],f[110][110];
int d[6][6]=
{
{0,0,0,0,0,0},
{0,5,-1,-2,-1,-3},
{0,-1,5,-3,-2,-4},
{0,-2,-3,5,-2,-2},
{0,-1,-2,-2,5,-1},
{0,-3,-4,-2,-1,0}
};
int main()
{
cin>>la;
for(int i=1;i<=la;i++)
{
char t;
cin>>t;
switch(t)
{
case'A':
a[i]=1;break;
case'C':
a[i]=2;break;
case'G':
a[i]=3;break;
case'T':
a[i]=4;break;
}
}
cin>>lb;
for(int i=1;i<=lb;i++)
{
char t;
cin>>t;
switch(t)
{
case'A':
b[i]=1;break;
case'C':
b[i]=2;break;
case'G':
b[i]=3;break;
case'T':
b[i]=4;break;
}
}
f[0][0]=0;
for(int i=1;i<=la;i++)
f[i][0]=f[i-1][0]+d[a[i]][5];
for(int i=1;i<=lb;i++)
f[0][i]=f[0][i-1]+d[5][b[i]];
for(int i=1;i<=la;i++)
for(int j=1;j<=lb;j++)
f[i][j]=max(f[i-1][j-1]+d[a[i]][b[j]],max(f[i-1][j]+d[a[i]][5],f[i][j-1]+d[5][b[j]]));
cout<<f[la][lb]<<endl;
return 0;
}
动态规划题。
若在第一段基因中插入空碱基相似度更优 则在第一段插入空碱基
若在第二段基因中插入空碱基相似度更优 则在第二段插入空碱基
若直接配对的相似度高于以上两者 则直接插入。
dp[i][j]=max(dp[i-1][j-1]+(i与j的匹配值),dp[i-1][j]+(i与空的匹配值),dp[i][j-1]+(j与空的匹配值)。
这周没做太多题,有些难题试了很多次没做出来,只能再回来找些适合自己的题继续练,比赛的题也看了,详解的思路都很清晰,看了几遍感觉还是有距离。