对于一个序列 a1 a2 ... an 我们可以计算出一个符号矩阵A, 其中Si,j 为 a1+...+aj 的正负号,(连加和大于0则Sij=+ 小于0 Sij=- 等于0 则Sij=0), 根据序列A不难算出上述符号矩阵。你的任务是求解它的“逆问题” , 及给出一个符号矩阵,找出一个对应的序列。输入保证存在一个满足条件的序列,其中每个整数的绝对值均不超过10
解 连续和转化为前缀和之差,设Bi=a1+...+ai 规定B0=0 则矩阵中的任意一项都等价于连个Bi 相减之后的正负号,例如 , 第x行y列的符号为正号 ax+...+ay>0 By-Bx-1>0, 转化为已知B0,B1,...,Bn,的一些大小关系,求他们的值,这个问题通过拓扑排序完成。
#include <iostream> #include <cstdio> #include <string.h> #include<vector> #include <algorithm> using namespace std; const int INF=50; char str[150]; vector<int> same[15]; vector<int> to[15]; int dgreed[15]; int G[15]; bool use[15]; int ans[15]; void solve(int loc, int v){ for(int i=0; i<same[loc].size(); ++i) ans[ same[loc][i] ]=v; } int main() { int cas; scanf("%d",&cas); for(int cc=1; cc<=cas; ++cc){ int n; scanf("%d",&n); scanf("%s",str); int loc=0; memset(dgreed,0,sizeof(dgreed)); memset(use,false,sizeof(use)); for(int i=0; i<=n; ++i) to[i].clear(),ans[i]=INF,same[i].clear(); for(int i=1; i<=n; ++i) for(int j=i; j<=n; ++j ){ if(str[loc]=='0'){ same[i-1].push_back(j); same[j].push_back(i-1); }else if(str[loc]=='+'){ to[i-1].push_back(j); dgreed[j]++; }else { to[j].push_back(i-1); dgreed[i-1]++; } loc++; } for(int i=0; i<n+1;++i){ int k=0; for(int j=0; j<n+1; ++j) if(use[j]==false&&dgreed[j]==0){ k=j; break; } G[i]=k; use[k]=true; for(int j=0; j<to[k].size(); ++j){ dgreed[to[k][j]]--; } } loc=0; for(int i=0; i<n+1; ++i) if(G[i]==0) { loc=i; break; } ans[0]=0; int v=-1; solve(0,0); for(int i=loc-1; i>=0; --i){ if(ans[ G[i] ] == INF){ ans[ G[i] ] =v--; } solve(G[i],ans[G[i]]); } v=1; for(int i=loc+1; i<=n; ++i){ if(ans[ G[i] ] == INF){ ans[ G[i] ] =v++; } solve(G[i],ans[G[i]]); } for(int i=1; i<=n ;++i) printf("%d%c",ans[i]-ans[i-1],i==n?' ':' '); } return 0; }