LA-4255 Guess (拓扑排序+构造)
题目大意:一个未知的整数序列,给出其任意一个区间和的正负,还原这个序列。任意一个满足条件的序列即可。
题目分析:将连续区间和转化为前缀和之差,sumx-1与sumy的大小关系已知,以此建立一条有向边,做拓扑排序。根据sum0=0,可以构造出所有的前缀和,再取两前缀和之差便得答案。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<vector> # include<cstring> # include<algorithm> using namespace std; char p[15][15]; int in[15],ans[15],mp[15][15],mp1[15][15]; vector<int>v; queue<int>q; void kahn(int n) { v.clear(); while(!q.empty()) q.pop(); for(int i=0;i<=n;++i) if(in[i]==0) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); v.push_back(u); for(int i=0;i<=n;++i){ if(mp[u][i]){ mp[u][i]=0; --in[i]; if(in[i]==0) q.push(i); } } } } void solve(int n) { ans[0]=0; int pos; for(int i=0;i<=n;++i){ if(v[i]==0){ pos=i; break; } } for(int i=pos-1;i>=0;--i){ if(!mp1[v[i]][v[i+1]])///如果跟相邻点没有明确的大小关系,则取相等。。下同。。。 ans[v[i]]=ans[v[i+1]]; else ans[v[i]]=ans[v[i+1]]-1; } for(int i=pos+1;i<=n;++i){ if(!mp1[v[i-1]][v[i]]) ans[v[i]]=ans[v[i-1]]; else ans[v[i]]=ans[v[i-1]]+1; } } int main() { int T,n; scanf("%d",&T); while(T--) { memset(in,0,sizeof(in)); memset(mp,0,sizeof(mp)); memset(mp1,0,sizeof(mp1)); scanf("%d",&n); getchar(); for(int i=0;i<n;++i){ for(int j=i+1;j<=n;++j){ p[i][j]=getchar(); if(p[i][j]=='+'){ mp1[i][j]=mp[i][j]=1; ++in[j]; } if(p[i][j]=='-'){ mp1[j][i]=mp[j][i]=1; ++in[i]; } } } kahn(n); solve(n); for(int i=1;i<=n;++i) printf("%d%c",ans[i]-ans[i-1],(i==n)?'\n':' '); } return 0; }