Description
对于一个序列a[1],a[2],…,a[n],我们可以计算出一个符号矩阵S,其中s[i][j]=a[i]+…+a[j]的正负号:连加和大于0则s[i][j]="+",小于0则s[i][j]="-",等于0则s[i][j]="0"。例如序列:-1,5,-4,2的矩阵如下:
根据序列A不难算出上述符号矩阵。你的任务上求解它的逆问题,即给出一个符号矩阵,找出一个对应的序列。输入保证存在一个满足上述条件的序列。可能满足的序列有多个,最大元素和最小元素尽量接近的解。
Input
第1行为整数T,表示数据组数。 每组数据包含两行,第1行为整数n,表示序列长度。第2行有n*(n+1)/2个字符,有符号矩阵的每一行按照从上到下的顺序连接而成。
Output
对于每组数据,在一行上输出n个绝对值不超过10的整数,即序列A。要求最大元素和最小元素尽量接近的解。
Sample Input 1
3 4 -+0++++--+ 2 +++ 5 ++0+-+-+--+-+--
Sample Output 1
-1 3 -2 1 1 1 1 1 -2 3 -4
Hint
本题的核心思路是转化。
s[i][j]为连续子序列和,可以转化为sum[j]-sum[i-1](前缀和)。
由题目所给信息可以判断出 sum[j] 与 sum[i-1] 的大小关系,于是可以把 sum 的下标看作图的顶点,
将 sum[i-1]<sum[j] 转化为由 i-1 到 j 的一条有向边。
因为图中不可能存在环,所以该图为DAG图,又因为A[i]=A[i]-A[i-1],
所以可以运用拓扑排序把sum计算出来,进而求得A序列。
需要注意的是要使序列中最大值与最小值尽量接近,且序列为整数,
则sum之间的最小差值为1,进行拓扑排序BFS,求得所有sum。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; const int maxn = 15; int n; vector<int> g[maxn]; int rd[maxn]; void input() { scanf("%d\n", &n); for(int i=0; i<=n; i++) rd[i] = 0, g[i].clear(); for(int i=1; i<=n; i++) for(int j=i; j<=n; j++) { char ch=getchar(); if(ch == ‘+‘) { g[i-1].push_back(j); rd[j]++; } else if(ch == ‘-‘) { g[j].push_back(i-1); rd[i-1]++; } } } int sum[maxn]; void BFS() { memset(sum, 0, sizeof(sum)); queue<int> Q; for(int i=0; i<=n; i++) if(!rd[i]) Q.push(i); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i=0; i<g[u].size(); i++) { int v = g[u][i]; sum[v] = max(sum[v], sum[u]+1); if(!--rd[v]) Q.push(v); } } } int main() { int t; scanf("%d", &t); while(t--) { input(); BFS(); for(int i=1; i<n; i++) printf("%d ", sum[i]-sum[i-1]); printf("%d\n", sum[n]-sum[n-1]); } return 0; } /* 3 4 -+0++++--+ 2 +++ 5 ++0+-+-+--+-+-- */
原文:https://www.cnblogs.com/de-compass/p/11800071.html