[CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities

Problem

每个点都可以选择降落士兵,然后当一个点的子节点被攻占的数量超过读入中的限制后,这个城市也被占领。
每个点降落士兵都有一定的代价,问把这一个图全部攻占的最小代价。

Solution

这显然和儿子有关还与父亲有关
我们假设f[x]表示x在父亲之前被攻占,g[x]表示x再父亲之后被攻占
显然有f[x]>=g[x]
在x放兵时,f[x]=g[x]=p[x]+∑gv
当x不放兵时,显然是在其儿子里选c[x]个取f[x](计算g[x]时为c[x]-1),剩下的取g[x]。排序即可。

Notice

感觉不是很好理解

Code

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define reg register int
#define rep(i, a, b) for (reg i = a; i <= b; i++)
#define per(i, a, b) for (reg i = a; i >= b; i--)
#define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
const int INF = 1e9, N = 5e4;
const double eps = 1e-6, phi = acos(-1);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
vector<int> edge[N + 5];
ll Val[N + 5], f[N + 5], g[N + 5];
int Limit[N + 5];
int cmp(int x, int y)
{
    return f[x] - g[x] < f[y] - g[y];
}
void dfs(int u, int fa)
{
    for (auto i = edge[u].begin(); i != edge[u].end();  i++)
        if (*i == fa) i = edge[u].erase(i) - 1;
        else dfs(*i, u);
}
void dp(int u)
{
    ll T = 0;
    for (auto i : edge[u]) dp(i), T += g[i];
    f[u] = g[u] = Val[u] + T;
    sort(edge[u].begin(), edge[u].end(), cmp);
    int p = edge[u].size();
    rep(i, 0, min(p, Limit[u] - 1) - 1) T += f[edge[u][i]] - g[edge[u][i]];
    if (Limit[u] - 1 <= edge[u].size()) g[u] = min(g[u], T);
    if (Limit[u] <= edge[u].size()) f[u] = min(f[u], T + f[edge[u][Limit[u] - 1]] - g[edge[u][Limit[u] - 1]]);
}
int sqz()
{
    int H_H = read();
    while (H_H--)
    {
        memset(f, 0, sizeof f);
        memset(g, 0, sizeof g);
        int n = read();
        rep(i, 1, n) edge[i].clear();
        rep(i, 1, n - 1)
        {
            int u = read(), v = read();
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        rep(i, 1, n) Val[i] = read();
        rep(i, 1, n) Limit[i] = read();
        dfs(1, 0);
        dp(1);
        write(f[1]); puts("");
    }
    return 0;
}

转载于:https://www.cnblogs.com/WizardCowboy/p/7756542.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值