Description
N children are living in a tree with exactly N nodes, on each node there lies either a boy or a girl. A girl is said to be protected, if the distance between the girl and her nearest boy is no more than D. You want to do something good, so that each girl on the tree will be protected. On each step, you can choose two nodes, and swap the children living on them. What is the minimum number of steps you have to take to fulfill your wish?
Input
The first line has a number T (T <= 150) , indicating the number of test cases. In a case, the first line contain two number n (1 <= n <= 50), D (1 <= D <= 10000000), Which means the number of the node and the distance between the girls and boys. The next lines contains n number. The i th number means the i th node contains a girl or a boy. (0 means girl 1 means boy), The follow n - 1 lines contains a, b, w, means a edge connect a th node and b th node, and the length of the edge is w (1 <= w <= 10000000).
Output
For every case, you should output "Case #t: " at first, without quotes. The t is the case number starting from 1. Then follows the answer, -1 meas you can't comlete it, and others means the minimum number of the times.
题目大意:一棵树上有n个结点,每个结点有一个男生或者一个妹纸,每条边有一个距离,问最少交换多少个人,使得妹纸在距离D内至少有一个男生。。。
思路:换句话说,这题可以理解为:交换多少个0或1,使得每个结点在D的距离内有一个1(1的男孩纸)。
那么用DLX搜索,每一列代表一个点。每一行代表一个点,每行的结点为这个点为1可以保护的所有点(包括自己)。
然后套DLX。
加入两个剪枝:搜索到的交换若大于当前答案,则剪枝。在每一层作一个乐观估计,估计最少还需要选出多少个点,若大于点为1的点数,则剪枝。
这题正解大概为DP。我不会。
代码(1171MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int MAXN = 55; 9 const int MAXC = MAXN; 10 const int MAXR = MAXN; 11 const int MAXP = MAXR * MAXN + MAXC; 12 13 int boy[MAXN]; 14 int mat[MAXN][MAXN]; 15 int n, D, boys; 16 17 struct DLX { 18 int n, sz;//列数,结点总数 19 int sum[MAXC];//每列拥有的结点数 20 int row[MAXP], col[MAXP];//结点所在的行和列 21 int left[MAXP], right[MAXP], up[MAXP], down[MAXP];//十字链表 22 int ans, anst[MAXR]; 23 24 void init(int nn) { 25 n = nn; 26 for(int i = 0; i <= n; ++i) { 27 up[i] = down[i] = i; 28 left[i] = i - 1; right[i] = i + 1; 29 col[i] = i; 30 } 31 right[n] = 0; left[0] = n; 32 sz = n + 1; 33 memset(sum, 0, sizeof(sum)); 34 } 35 36 void add_row(int r, vector<int> &columns) { 37 int first = sz; 38 for(int i = 0, len = columns.size(); i < len; ++i) { 39 int c = columns[i]; 40 left[sz] = sz - 1; right[sz] = sz + 1; down[sz] = c; up[sz] = up[c]; 41 down[up[c]] = sz; up[c] = sz; 42 row[sz] = r; col[sz] = c; 43 ++sum[c]; ++sz; 44 } 45 right[sz - 1] = first; left[first] = sz - 1; 46 } 47 48 void remove(int c) { 49 for(int i = down[c]; i != c; i = down[i]) { 50 left[right[i]] = left[i]; 51 right[left[i]] = right[i]; 52 } 53 } 54 55 void restore(int c) { 56 for(int i = down[c]; i != c; i = down[i]) { 57 left[right[i]] = i; 58 right[left[i]] = i; 59 } 60 } 61 62 bool vis[MAXC]; 63 64 int A() { 65 memset(vis, 0, sizeof(vis)); 66 int ret = 0; 67 for(int i = right[0]; i != 0; i = right[i]) if(!vis[i]) { 68 ++ret; 69 for(int j = down[i]; j != i; j = down[j]) { 70 for(int k = right[j]; k != j; k = right[k]) vis[col[k]] = true; 71 } 72 } 73 return ret; 74 } 75 76 void dfs(int dep) { 77 if(dep + A() > boys) return ; 78 int tmp = 0; 79 for(int i = 0; i < dep; ++i) tmp += boy[anst[i]]; 80 if(dep - tmp >= ans) return ; 81 if(right[0] == 0) { 82 ans = dep - tmp; 83 return ; 84 } 85 int c = right[0]; 86 for(int i = right[0]; i != 0; i = right[i]) if(sum[i] < sum[c]) c = i; 87 for(int i = down[c]; i != c; i = down[i]) { 88 anst[dep] = row[i]; 89 remove(i); 90 for(int j = right[i]; j != i; j = right[j]) remove(j); 91 dfs(dep + 1); 92 for(int j = left[i]; j != i; j = left[j]) restore(j); 93 restore(i); 94 } 95 } 96 97 bool solve() { 98 ans = n + 1; 99 dfs(0); 100 return ans != n + 1; 101 } 102 } S; 103 104 void floyd() { 105 for(int k = 1; k <= n; ++k) 106 for(int i = 1; i <= n; ++i) if(mat[i][k] <= D) 107 for(int j = 1; j <= n; ++j) if(mat[k][j] <= D) 108 mat[i][j] = min(mat[i][j], mat[i][k] + mat[k][j]); 109 } 110 111 int main() { 112 int T; scanf("%d", &T); 113 for(int t = 1; t <= T; ++t) { 114 scanf("%d%d", &n, &D); 115 memset(mat, 0x3f, sizeof(mat)); 116 boys = 0; 117 for(int i = 1; i <= n; ++i) scanf("%d", &boy[i]), boys += boy[i]; 118 for(int i = 1; i < n; ++i) { 119 int u, v, c; 120 scanf("%d%d%d", &u, &v, &c); 121 mat[u][v] = mat[v][u] = c; 122 } 123 for(int i = 1; i <= n; ++i) mat[i][i] = 0; 124 floyd(); 125 S.init(n); 126 for(int i = 1; i <= n; ++i) { 127 vector<int> columns; 128 for(int j = 1; j <= n; ++j) if(mat[i][j] <= D) columns.push_back(j); 129 S.add_row(i, columns); 130 } 131 bool flag = S.solve(); 132 printf("Case #%d: ", t); 133 if(flag) printf("%d ", S.ans); 134 else puts("-1"); 135 } 136 }