分治法或拓扑排序 poj1463 Strategic game

来源:互联网 发布:手机cad软件下载 编辑:程序博客网 时间:2024/06/05 17:10

刚开始以为是覆盖点,,,后来才发现原来是覆盖边,,汗,错了这么多次


我写了两种方法,,其实还可以用二分图匹配写的,,就没写了

第一种方法是分治法,,具体是这样的

我们设计一个函数,能求出当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;}


0 0
原创粉丝点击