HDU 4735 Little Wish~ lyrical step~(DLX搜索)(2013 ACM/ICPC Asia Regional Chengdu Online)

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\n", S.ans);

134         else puts("-1");

135     }

136 }
View Code

 

你可能感兴趣的:(online)