题意
n个点,m个关系。a依赖b则a需要出现在b前。
求满足所有关系的最短序列长度。
n<18, m<n(n-1)
题解
问题事实上等价于有向有环图的拓扑排序。
所以用拓扑排序结合搜索有个显然的2^n*n^2的做法。
赛场上写的有点丑T了。
标算是DP。F[S]表示添加了集合S的最短长度。对于每个S,枚举添加点x:若x被依赖的所有点都出现过,则只需要在当前序列最后添加x;否则,需要在最后再添加一个x使尚未添加的点满足条件。
复杂度O(2^n*n)。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int h[30], f[300000]; 5 6 int main() 7 { 8 int T; 9 for (scanf("%d", &T); T; T--) 10 { 11 memset(h, 0, sizeof(h)); 12 int n, m; 13 scanf("%d%d", &n, &m); 14 for (int i = 0; i < m; ++i) 15 { 16 int u, v; 17 scanf("%d%d", &u, &v); 18 h[v] ^= 1 << (u - 1); 19 } 20 int maxx(pow(2, n)); 21 for (int i = 0; i < maxx; ++i) 22 f[i] = 2 * n; 23 f[0] = 0; 24 for (int i = 0; i < maxx; ++i) 25 for (int j = 1; j <= n; ++j) 26 if (!(i & (1 << (j - 1)))) 27 if ((h[j] ^ i) & h[j]) 28 f[i ^ (1 << (j - 1))] = min(f[i ^ (1 << (j - 1))], f[i] + 2); 29 else 30 f[i ^ (1 << (j - 1))] = min(f[i ^ (1 << (j - 1))], f[i] + 1); 31 printf("%d ", f[maxx - 1]); 32 } 33 34 return 0; 35 }