A题
思路
其实是一道括号匹配题,可以使用数据结构的栈。
- 如果是’(’,入栈。
- 如果是’)’,栈非空则出栈。栈空则累加多余括号。
- 最后加上栈中剩余元素和。
代码&解释
int t,n,i;
int main()
{
scanf("%d",&t);
while(t--){
int z=0,cnt=0;//z表示虚拟栈中元素,cnt累加多余的')'
scanf("%d",&n);
char c[n];
getchar();
scanf("%s",c);
for(i=0;i<n;i++){
if(c[i]=='(')z++;//左括号进栈
else if(z>0)z--;//栈非空出栈
else cnt++;//累加多余')'
}
printf("%d\n",cnt+z);
}
return 0;
}
总结
- 有时候可以模拟栈不需要用真正的栈,
虽然代码可读性下降了但节约了栈操作的时间。 不要用gets!用scanf("%s")读入无空格字符串。
B题
思路
这题相当于统计构成路的条数,这里提示了使用并查集。
- 罐子中钥匙存储形成的路必以成环结束,有两种可能:一是自身把钥匙放在自己里面
虽然不知道怎么做到的,二是和其他罐子围成环。 - 每个结点找他们的各自的爹的暂时终极爹,找到了过后让他做自己的爹,我愿称之为
你和你爹平起平坐压缩路径不然每次都要重复走会tle的。 - 一开始令自己的终极爹是自己,表示自己还未被访问。
代码里的终极爹是成环后血缘链的顶端
代码&解释
int n,b[1000001],f[1000001],i,cnt;//b是暂时爸爸,f是终极爹
int find_f(int x){
if(f[x]==x)return x;//第一次访问或自己是自己的爹
return f[x]=find_f(f[x]);//爹有别的爹,找爹并且认爹
}
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&b[i]);//暂时爸爸
f[i]=i;//开局自己是自己的暂时终极爹
}
for(i=1;i<=n;i++){
if(find_f(b[i])==i){//爹的终极爹是自己
cnt++;//构成一条血缘链
}else f[i]=b[i];//没有找到终极爹,让暂时爸爸做暂时终极爹
}
printf("%d\n",cnt);
return 0;
}
总结
- 判断找爸爸的结束情况,让并查集能够结束递归。
- 每次找完爸爸都要压缩路径,不然重复的递归浪费时间。