图论训练1A,uva4255 拓扑排序

Given a sequence of integers, a1a2,..., an , we define its sign matrix S such that, for 1$ \le$i$ \le$j$ \le$n , Sij = `` + " if ai +...+ aj > 0 ; Sij = `` - " ifai +...+ aj < 0 ; and Sij = ``0" otherwise.

For example, if (a1a2a3a4) = (- 1, 5, - 4, 2) , then its sign matrix S is a 4×4 matrix:


 1234
1-+0+
2 +++
3  --
4   +


We say that the sequence (-1, 5, -4, 2) generates the sign matrix. A sign matrix is valid if it can be generated by a sequence of integers.

Given a sequence of integers, it is easy to compute its sign matrix. This problem is about the opposite direction: Given a valid sign matrix, find a sequence of integers that generates the sign matrix. Note that two or more different sequences of integers can generate the same sign matrix. For example, the sequence (-2, 5, -3, 1) generates the same sign matrix as the sequence (-1,5, -4,2).

Write a program that, given a valid sign matrix, can find a sequence of integers that generates the sign matrix. You may assume that every integer in a sequence is between -10 and 10, both inclusive.

Input

Your program is to read from standard input. The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case consists of two lines. The first line contains an integer n(1$ \le$n$ \le$10) , where n is the length of a sequence of integers. The second line contains a string of n(n + 1)/2 characters such that the first n characters correspond to the first row of the sign matrix, the next n - 1 characters to the second row, ... , and the last character to the n -th row.

Output

Your program is to write to standard output. For each test case, output exactly one line containing a sequence of n integers which generates the sign matrix. If more than one sequence generates the sign matrix, you may output any one of them. Every integer in the sequence must be between -10 and 10, both inclusive.

Sample Input

3 
4 
-+0++++--+ 
2 
+++ 
5 
++0+-+-+--+-+--

Sample Output

-2 5 -3 1 
3 4 
1 2 -3 4 -5
 
  
 对于一个序列a1,a2,a3,....an,我们可以计算出一个符号矩阵S,就是上面右图矩阵,其中S(i,j)表示  ai+...+aj的正负号,给出序列不难求出矩阵,我们的任务是求出“逆问题”,即给出矩阵,求出序列,序列每个值大于-10小于10;

				 
   			        T0   T1   T2   T3  T4
(我在最前面加了一个0表示T00          -          +         0      +
-2   5  -3   1      --->	           +    +   +			
 				                -   -
				                    +
 
  
     如果用T(k)表示序列前k项和,那么S(i,j)=  T(j )- T(i-1);S(i,j)正负知道,那么T(j)-T(i-1)的正负也就知道了,如果T(j)-T(i-1)='-',可以得出T(j)>T(i-1),让j指向i-1,建立边,可以得到一个拓扑排序图,
       拓扑排序中被指向的点小于指向它的点,如果一个点没有任何点指向它,那么他是最大点,将拓扑排序最低端点赋值为10,因为每个序列中每个点都小于10 ,第二层T()值比最低端T()值小1,最多最多10层,做差肯定在-10~10之间,
       以第一个样例分析
       
     拓扑排序图解释,最底层是第一层,然后第二层,第三层,第四层,T(2)=10,T(4)=9,T(0)=8,T(3)=8,T(1)=7;  a(1)=T(1)-T(0)=-1,a(2)=T(2)-T(1)=3,a(3)=-1.a(4)=1;
   序列:  -1,3,-2,-1;符合题意,输出任意一种序列就可以了,题目输出就是这么说的;
		代码:
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <cmath>
#include <stdlib.h>
using namespace std;
const int maxn=305;
int sum[maxn];///表示前n项和

char str[maxn];
int d[maxn];
int  head[maxn],tot;
struct Edge
{
    int v,next;
}edge[maxn];
void init(int n)
{
    tot=0;
     memset(head,-1,sizeof(head));
     for(int i=0;i<=n;i++)
        sum[i]=10;
}
void addedge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void topo(int n)
{
    queue<int>que;
    for(int i=0;i<=n;i++)
        if(d[i]==0)
        que.push(i);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            sum[v]=sum[u]-1;
            d[v]--;
            if(d[v]==0)
                que.push(v);

        }
    }
}
int main()
{
    int t,n;
    int ans[maxn];
    cin>>t;
    while(t--)
    {
        cin>>n;
        cin>>str;
        int k=0;
        memset(d,0,sizeof(d));
        init(n);
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++,k++)
            {
                if(str[k]=='-')///Si>Sj
                {
                    addedge(i-1,j);
                    d[j]++;
                }
                else if(str[k]=='+')///Sj>Si
                {
                    addedge(j,i-1);
                    d[i-1]++;
                }
            }
        }
        topo(n);
        for(int i=1;i<=n;i++)
            ans[i]=sum[i]-sum[i-1];
        cout<<ans[1];
        for(int i=2;i<=n;i++)
            cout<<" "<<ans[i];
        cout<<endl;
    }
    return 0;
}


 
  
 
  
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值