ZOJ-1016-Parencodings

题目大意:

对于一个良好组织的圆括号字符串S,有两种编码方式:
P方式:
P = p1 p2 … pn,这里pi是第i个右圆括号之前左圆括号的数量
W方式
W = w1 w2 … wn,这里举个例子,比如S中第i个右圆括号a,我们记录这个整数:从与a匹配的左圆括号数起,到a为止,中间右圆括号的数量。
要求从P编码转到W编码

方法一:
由p序列构造出字符串s,再由s得出w序列
遍历数组,依次找出每个‘)’,然后从当前位置逆向查找,如果找到了一个‘(’,我们需要判断该‘(’是否已经配对,配对信息用used数组记录,如果已经配对,则说明该‘(’已经对应了一个‘)’,结果加1,否则该‘(’与‘)’配对,匹配找到,退出循环。

#include <cstdio>
#include <string>
#include <cstring>
using namespace std;

string PtoS(int n, int *p){
	int count = 0;
	string s = "";
	for(int i = 0; i < n; i++){
		while(count < p[i]){
			s += '('; 
			count++;
		}
		s += ')';
	}
	return s; 
}

void StoW(int n, string s){
	int used[2*n];
	int w[n+2];
	int pos = 0;
	memset(used, 0, sizeof(used));
	memset(w, 0, sizeof(w));
	for(int i = 0; i < 2*n; i++){
		if(s[i] == ')'){
			for(int j = i-1; j >= 0; j--){
				if(s[j] == '('){
					if(used[j] == 1)
						w[pos]++;
					else{
						++w[pos];
						printf("%d", w[pos]);
						if(i != 2*n -1)
							printf(" "); 
						++pos;
						used[j] = 1;
						break;
					}
				}
			}
			
		}
	}
	printf("\n");
	return;
} 

int main(){
	//freopen("tmp.txt", "r", stdin);
	int t, n;
	scanf("%d", &t);
	while(t--){	
			
		scanf("%d", &n);
		int p[n];
		for(int i = 0; i < n; i++){
			scanf("%d", &p[i]);
		}
			
		string parent = PtoS(n, p);
		StoW(n, parent);
		
	}	
} 

方法二:
由于括号序列是完全匹配的
所以有多少右括号就有多少左括号
P序列输入的是每一个右括号前左括号的个数
要求的是从与他匹配的左括号开始到他自身的右括号的个数
所以可以设一个左括号序列用右括号跟他匹配
对于每一个P
他的左边肯定有p个左括号
跟他匹配的就是从第p个开始的往前数第一个未被匹配的左括号
找到后标记一下
而从这个左括号开始到p的右括号的个数正好就是他们之间已经匹配的括号对数+1
具体做法如下
用一个数组left[]记录左括号的匹配情况
初始化为零表示都没有匹配
然后读入一个p就从left[p]开始查找第一个left[j]==0
然后p-j+1就是从与他匹配的左括号到他自身的右括号的个数
最后把left[j]赋值为1表示已经匹配成功

#include <cstdio>
#include <string>
#include <cstring>

using namespace std;

int main(){
	//freopen("tmp.txt", "r", stdin);
	int left[25], i, first, t, n, p;
	scanf("%d", &t);
	while(t--)
	{
	    memset(left,0,sizeof(left));
	    first=1;
	    scanf("%d", &n);
	    while(n--)
	    {
	                scanf("%d", &p);
					i = p;
	                while(left[i]) i--;
	                if(first){
						printf("%d", p-i+1);
						first=0;
					}
	                else printf(" %d", p-i+1);
	                left[i]=1;
	    }              
	    printf("\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值