Uvalive 4255 - Guess(思维+拓扑排序)
题目链接 https://vjudge.net/problem/UVALive-4255
【题意】
对于一个序列a1,a2…an,我们可以计算出一个符号矩阵s,s[i][j]为ai+…+aj的正负号,现在给出一个符号矩阵,求一个满足该符号矩阵的序列,每个整数的绝对值不超过10.
【思路】
大白书310页例题,将连续和转为前缀和,即ai+…+aj=b[j]-b[i-1],然后根据符号矩阵即可得出一些b[i]和b[j]的大小关系,用小于关系作为边建立有向图,那么这个图的拓扑排序序列便是一个可行解,因为n<=10,所以顶点编号最大只有10。用队列进行拓扑排序,将入度为0的顶点加入队列,再删除这些结点和其它结点之间的有向边,重复这一过程。在拓扑排序时,如果存在e=(u,v)的有向边,说明顶点v一定在u之后,让b[v]=b[u]+1,这样经过整个排序后就会得到一个符合要求的前缀和序列。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 15;
int n;
char s[maxn*maxn];
int b[maxn];
int inDegree[maxn];
int g[maxn][maxn];
void init() {
memset(b, 0, sizeof(b));//把前缀和先全部初始化为0
memset(inDegree, 0, sizeof(inDegree));
memset(g, 0, sizeof(g));
}
void toposort() {
queue<int> que;
while (!que.empty()) que.pop();
for (int i = 0; i <= n; ++i) {
if (0 == inDegree[i]) que.push(i);
}
while (!que.empty()) {
int u = que.front();
que.pop();
for (int i = 0; i <= n; ++i) {
if (g[u][i] == 1) {
b[i] = b[u] + 1;
--inDegree[i];
if (0 == inDegree[i]) que.push(i);
}
}
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
init();
scanf("%d%s", &n, s);
for (int i = 1, k = 0; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if (s[k] == '+') {
g[i - 1][j] = 1;
++inDegree[j];
}
else if (s[k] == '-') {
g[j][i - 1] = 1;
++inDegree[i - 1];
}
++k;
}
}
toposort();
for (int i = 1; i <= n; ++i) {
printf("%d%c", b[i] - b[i - 1], i == n ? '\n' : ' ');
}
}
return 0;
}