您的位置:首页 > 其它

poj-1068 Parencodings 动态规划

2018-02-07 19:52 381 查看

题目链接

poj-1068 Parencodings

题目

Parencodings

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 27610 Accepted: 16233
Description

Let S = s1 s2...s2n be a well-formed string of parentheses. S can be encoded in two different ways: 

q By an integer sequence P = p1 p2...pn where pi is the number of left parentheses before the ith right parenthesis in S (P-sequence). 

q By an integer sequence W = w1 w2...wn where for each right parenthesis, say a in S, we associate an integer which is the number of right parentheses counting from the matched left parenthesis of a up to a. (W-sequence). 

Following is an example of the above encodings: 
S		(((()()())))

P-sequence	    4 5 6666

W-sequence	    1 1 1456


Write a program to convert P-sequence of a well-formed string to the W-sequence of the same string. 

Input

The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case is an integer n (1 <= n <= 20), and the second line is the P-sequence of a well-formed
string. It contains n positive integers, separated with blanks, representing the P-sequence.

Output

The output file consists of exactly t lines corresponding to test cases. For each test case, the output line should contain n integers describing the W-sequence of the string corresponding to its given P-sequence.

Sample Input
2
6
4 5 6 6 6 6
9
4 6 6 6 6 8 9 9 9


Sample Output
1 1 1 4 5 6
1 1 2 4 5 1 1 3 9


Source

Tehran 2001

题意

给出一个串S,总长度为2*n,全部由括号组成。根据串S可以得到串P,P的长度为n,P[i] = v表示第i+1个右括号的前面有v个左括号。要求输入串P,得到串W。W[i] = v表示第i+1个右括号能包括到几个数(此处翻译无力,直接看例子):
 (()())

第一个右括号对应W值为1,第二个右括号对应W值为1,第三个右括号对应W值为3
就是说一对括号的值=1+里面的括号对数。

要求输入串P,输出串W。

题解

对于S,我们可以得到P为对应的一个数组,如果我们将左括号的值设定为0,右括号的值是S值,那么对于sample 2可以得到



实际上考虑模拟法,我们就是写出算法来模拟平常算的时候的操作。我们手算该题的时候考虑怎么计算呢?先找第一个右括号,
然后向前寻找匹配,发现恰好有一个左括号匹配,就说明此处的M值为1。如果在向左找的时候发现又有一个右括号,那么就要
找2个左括号匹配。此时还要考虑括号里面有括号的情况下,总数应该如何计算。
如果我们分解问题,考虑从右括号向左找的时候,碰见一个右括号,直接找到这个右括号对应的左括号,这样就不用考虑碰到的
括号里面具体是什么情况,只用知道这个括号的值是多少,+1就是原括号的值了。
上一段重复进行,直到碰见一个左括号,恰好与右括号匹配。

上面一段看不懂没关系,我们先对sample 2分析画图分析一下:
1.初始化M串令其元素全部为0
2.找到第一个有右括号的对应的M串处
3.向前寻找左括号,找到则令左括号与右括号在M串所在位置的值更新为:寻找过程中碰见的括号对的值之和+1。如果没有碰见
左括号,那就把当前右括号对应的值累加,同时跳跃到碰见的右括号对应的左括号出。
可以看下图:(忽略字体。。)



可看这一段代码:

for (i = 0; i < n; i++) {
int num = 0;
int flag = ans[i] - 1;
while (MP[flag] != 0) {
int temp = MP[flag];
flag--;
for (; MP[flag] != temp; flag--);
num += temp;
flag--;
}
MP[flag] = num + 1;
MP[ans[i]] = num + 1;
}


int flag就表示指针,模拟向前遍历,while循环判断是否找到未匹配的左括号(如果没有匹配,就是初始化的0,如果已经匹配,
那么至少为1)。for循环是在找到一个右括号的时候,遍历寻找对应的左括号。第一个与其值相同的一定是对应的左括号。然后
再从这个左括号的位置继续向左遍历,直到碰见空的左括号。每次遍历的时候num一直在完成累加的工作,记录这个括号包括了
几个括号,它们的值分别为多少。最终,将得到的值存放进去。

C++代码 0ms

 #include<iostream>
#include<vector>
#include<string>
#include<cmath>
#include<algorithm>
#define TIME std::ios::sync_with_stdio(false);
#define LL long long
#define N 22

using namespace std;

int MP[2 * N];
int TMP[2 * N];
int ans
;

int main() {
TIME
int T, n;
cin >> T;
while (T--) {
memset(MP, 0, sizeof(MP));
memset(TMP, 0, sizeof(TMP));
memset(ans, 0, sizeof(ans));
cin >> n;
int last = 0;
int i, j, now;
for (i = 0, j = 0; i < n; i++) {
cin >> now;
int temp = now - last;
j = j + temp + 1;
TMP[j] = now;
ans[i] = j;
last = now;
}
for (i = 0; i < n; i++) { int num = 0; int flag = ans[i] - 1; while (MP[flag] != 0) { int temp = MP[flag]; flag--; for (; MP[flag] != temp; flag--); num += temp; flag--; } MP[flag] = num + 1; MP[ans[i]] = num + 1; }
for (i = 0; i < n; i++) {
cout << MP[ans[i]];
if (i == n - 1) {
cout << endl;
}else {
cout << " ";
}
}
}

system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: