刚开始以为是覆盖点,,,后来才发现原来是覆盖边,,汗,错了这么多次
我写了两种方法,,其实还可以用二分图匹配写的,,就没写了
第一种方法是分治法,,具体是这样的
我们设计一个函数,能求出当i为根节点时候的子树中,i放士兵时,整个子树士兵最小数量,以及i不放士兵时,整个子树士兵最小数量
那么通过求子树的答案,然后把答案合并到根节点呢
设根节点放士兵的最小数量为a,不放士兵的最小数量为b
那么对于b,说明子树的根必须都要放士兵才行,所以b+=子节点的a
对于a,因为本身已经放了,所以子树放什么都不是很重要,所以a+=min(子节点的a,子节点的b),最后再加1(在自己的根放了一个)
最后的答案就是在a,b中取最小值了
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<ctime> #include<functional> #include<algorithm> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 1500 + 5; const int INF = 0x3f3f3f3f; vector<int>G[MX]; int vis[MX]; void solve(int u, int &a, int &b) { a = 0; b = 1; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; int na, nb; solve(v, na, nb); a += nb; b += min(na, nb); } } int main() { int n; //freopen("input.txt","r",stdin); while(~scanf("%d", &n)) { memset(vis, 0, sizeof(vis)); for(int i = 0; i <= n; i++) { G[i].clear(); } for(int i = 0; i < n; i++) { int u, v, num; scanf("%d:(%d)", &u, &num); for(int j = 1; j <= num; j++) { scanf("%d", &v); G[u].push_back(v); vis[v] = 1; } } int root; for(int i = 0; i < n; i++) { if(!vis[i]) { root = i; break; } } int a, b; solve(root, a, b); printf("%d\n", min(a, b)); } return 0; }
可以想象,在入度为0的点,如果让他们不放士兵,那么答案一定不会变差。
所以可以通过这一点按照拓扑序求答案
在更新一个点后,把它的父节点的入度减一,如果此时入度为0了就加入到队列中
如果本身没放士兵,那么父节点必须要放士兵
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<ctime> #include<functional> #include<algorithm> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 1500 + 5; const int INF = 0x3f3f3f3f; int p[MX], IN[MX], col[MX]; int main() { int n; //freopen("input.txt", "r", stdin); while(~scanf("%d", &n)) { memset(IN, 0, sizeof(IN)); memset(p, -1, sizeof(p)); memset(col, 0, sizeof(col)); for(int i = 0; i < n; i++) { int u, v, num; scanf("%d:(%d)", &u, &num); for(int j = 1; j <= num; j++) { scanf("%d", &v); p[v] = u; IN[u]++; } } queue<int>work; for(int i = 0; i < n; i++) { if(p[i] != -1 && !IN[i]) { work.push(i); } } int ans = 0; while(!work.empty()) { int f = work.front(); work.pop(); ans += col[f]; if(p[f] != -1) { int v = p[f]; col[v] |= col[f] ^ 1; IN[v]--; if(!IN[v]) { work.push(v); } } } printf("%d\n", ans); } return 0; }