HDU 5290 Bombing plan

题意
X国有n(n<105)个城市,用n-1条无向边连接。城市i有一个权值wi(wi<100),如果炸毁城市i,那么距离i不超过wi的节点也会被炸毁。求炸毁所有城市最少需要炸几次。
Solution
相比前几天做的SGU 280 不同之处在与这题对每个点有不同的k。

但这一题不能贪心,只能采用dp的方法。形式上却也差不多,都是对子树的讨论。令f[i][j]为以i为根的子树,能向子树外拓展i个节点最少需要炸毁几个城市。G[i][j]为以i为根的子树,子树内有节点未被炸毁,且距离根为j最少需要炸毁几个城市。

转移方程:

不炸毁u点

f[u][j]=f[v][j+1]+min(f[k][0 j+1],G[k][0 j]);

G[u][0]=f[u][0];

G[u][j]=G[v][j?1]+min(f[k][0 j?1],G[k][0 j?1]);

炸毁u点

f[u][w[u]]=1+min(f[v][0 w[u]+1],G[v][w[u]]);

这里需要对f[][]和G[][],求前缀最小值。

节点比较多,避免爆栈不能直接用递归的方法做。

时间复杂度O(n?w)

Bombing plan

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 364    Accepted Submission(s): 86

Problem Description

Kingdom Y is in the war with kingdom X. Kingdom X consists of N cities,there are N-1 bidirectional roads which are all 1 long ,each of them connect a pair of cities,the N cities are all connect by the N-1 bidirectional.People can travel through the roads.

Now kingdom Y is going to bomb kingdom X. Every city of kingdom X has its own value W. If city i was to be bombed, then all the cities that lie within the distance W(i) from city i would be destroyed as well. The king of kingdom Y wants to know the minimum
bombing time that can destroy all the cities in kingdom X. Could you help him?

Input

There are multiple test cases. Please process till EOF.

In each test case:

First line: an integer n(n<=10^5) indicating the number of city

Second line:contain n numbers w[i](0<=w[i]<=100) ,indicating that the value of city[i],

Next n - 1 lines: each contains two numbers ui and vi, (1 ≤ ui,vi<=n), indicates that there’s one road connecting city ui and vi.

Output

For each case,output one number, denotes the minimum number of bombing times.

Sample Input

5
1 1 1 1 1
1 2
2 3
3 4
4 5

Sample Output

2

Author

FZUACM

Source

2015 Multi-University Training Contest 1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define prt(k) cout<<#k" = "<<k<<endl;
const int inf = 0x3f3f3f3f;
const int N = 100007;
const int W = 107;
int f[N][107], g[N][107];
int father[N];
int n;
int w[N];
int F[N][107], G[N][107];
int maxw;
struct edge
{
        int v, next;
}e[N<<1];
int head[N], mm;
void add(int u,  int v)
{
        e[mm].v = v;
        e[mm].next = head[u];
        head[u] = mm++;
}
struct P
{
        int d, id;
        P() {}
        P(int _id, int _d=0) { d=_d, id=_id; }
        bool operator < (P b) const
        {
                return d > b.d;
        }
}p[N];
bool vis[N];
void bfs()
{
        queue<P> q;
        q.push(P(1,0));
        memset(vis,0,sizeof vis);
        vis[1] = true;
        father[1] = 1;
        while (!q.empty()) {
                P u = q.front(); q.pop();
                int now = u.id;
                p[now].id = now;
                p[now].d = u.d + 1;
                for (int i=head[now];~i;i=e[i].next) {
                        int v = e[i].v;
                        if (!vis[v]) {
                                q.push(P(v, u.d + 1));
                                vis[v] = true;
                                father[v] = now;
                        }
                }
        }
}
void gao(int u, int fa)
{
        assert(!vis[u]);
        vis[u] = true;
        bool flag = false;
        for (int i=head[u];~i;i=e[i].next) {
                int v = e[i].v;
                if (v==fa) continue;
                flag = true;
                assert(vis[v]);
        }
        if (!flag) {
                g[u][0] = 0;
                f[u][w[u]] = 1;
        }
        for (int j=0;j<=maxw;j++) {
                ll sum=0;
                for (int i=head[u];~i;i=e[i].next) {
                        int v = e[i].v;
                        if (v==fa) continue;
                        int t = F[v][j+1];
                        if (j > 0)
                                t = min(t, G[v][j-1]);
                        sum += t;
                        if (sum >= inf) { sum = inf; break; }
                }
                if (sum < inf ) for (int i=head[u];~i;i=e[i].next) {
                        int v = e[i].v;
                        if (v==fa) continue;
                        int t = F[v][j+1];
                        if (j > 0) t = min(t, G[v][j-1]);
                        if (0<=sum && sum < inf) f[u][j] = min(f[u][j], (int)(f[v][j+1] + sum - t ) ) ;
                }
                sum = 0;
                int t;
                for (int i=head[u];~i;i=e[i].next) {
                        int v = e[i].v;
                        if (v==fa) continue;
                        int t = F[v][j];
                        if (j > 0) t = min(t, G[v][j-1]);
                        sum += t;
                        if (sum >= inf)  { sum = inf; break; }
                }
                if (j>0 && sum < inf) for (int i=head[u];~i;i=e[i].next) {
                        int v = e[i].v;
                        if (v==fa) continue;
                        int t = F[v][j];
                        if (j > 0) t = min(t, G[v][j-1]);
                        if (0<=sum && sum < inf) g[u][j]=min(g[u][j], (int)(g[v][j-1] + sum -  t ) );
                }
        }
        ll sum = 0;
        for (int i=head[u];~i;i=e[i].next) {
                int v = e[i].v;
                if (v==fa) continue;
                sum += min(F[v][w[u]+1], w[u]>0 ? G[v][w[u]-1] : inf);
        }
        if (0<=sum && sum<inf) f[u][w[u]]=min(f[u][w[u]], int(1 +  sum ));
        F[u][0] = f[u][0];
        G[u][0] = g[u][0];
        for (int j=1;j<=maxw+1;j++) {
                F[u][j] = min(F[u][j-1], f[u][j]);
                G[u][j] = min(G[u][j-1], g[u][j]);
        }
}
int main()
{
        while (scanf("%d", &n)==1) {
                maxw = 0;
                for (int i=1;i<=n;i++) scanf("%d", w+i), maxw=max(maxw, w[i]);
                mm=0; memset(head,-1,sizeof head);
                for (int i=1;i<=n-1;i++)
                {
                        int u, v; scanf("%d%d", &u, &v);
                        add(u, v);
                        add(v, u);
                }
                memset(f, 63, sizeof f);
                memset(g, 63, sizeof g);
                bfs();
                sort(p+1, p+n+1);
                memset(vis, 0, sizeof vis);
                for (int i=1;i<=n;i++) {
                        gao(p[i].id, father[p[i].id]);
                }
                int ans = n;
                for (int i=0;i<=maxw;i++)
                        ans =  min(ans, f[1][i]);
                printf("%d\n", ans);
        }
}
/**
3
1 1 1
1 2
2 3
7
1 1 1 1 1 1 1
1 2
2 3
3 4
4 5
5 6
6 7
4
0 1 0 1
1 2
1 3
1 4
4
0 2 0 0
1 2
1 3
1 4

*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 21:38:11

HDU 5290 Bombing plan的相关文章

hdu 5290 Bombing plan(树形dp)

题目链接:hdu 5290 Bombing plan dpDestroy[u][i]表示以u为根节点的子树全部被摧毁,并且向上还可以破坏到距离u为i的城市:dpSafe[u][i]表示以u为根节点的子树中有距离u深度为i的城市还未被破坏. dpDestroy[u][i] = dpDestroy[v][i+1] + sum{ min(dpDestroy[k][j], dpSafe[k][j])(j≤i)| k为除了v以外的子节点} dpSafe[u][i] = dpSafe[v][i-1] + s

HDU 5290 Bombing plan 树形dp

题目链接 题意 给定n个点的树,每个点有一个点权wi, 每次选一个点u,则树上u和距离u wi范围内的所有点都会被染色. 问:最少选几个点使得n个点都被染色. 思路:树形dp 对于某个点u down[u][j] 表示u以及u向下深度为 j 的点没有被染色的最小花费. up[u][j] 表示u以及u向上距离为j的点已经被染色的最小花费. 设u点的儿子们为v, v2, v3 ···,每个点点权为w[]数组 3种转移: 1.对于down[u][i] 显然就是子树的down数组求和,特殊一点就是down

HDU 4022 Bombing(基本算法-水题)

Bombing Problem Description It's a cruel war which killed millions of people and ruined series of cities. In order to stop it, let's bomb the opponent's base. It seems not to be a hard work in circumstances of street battles, however, you'll be encou

HDU 4022 Bombing STL 模拟题

手动模拟.. #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #include<map> using namespace std; #define N 10100 #define inf 1000000010 map<

hdu 4022 Bombing (离散化)

Bombing Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 3176    Accepted Submission(s): 1195 Problem Description It’s a cruel war which killed millions of people and ruined series of cities. In

HDU 4022 Bombing(stl,map,multiset,iterater遍历)

题目 参考了     1     2 #define _CRT_SECURE_NO_WARNINGS //用的是STL中的map 和 multiset 来做的,代码写起来比较简洁,也比较好容易理解. //multiset可以允许重复 //multiset<int>::iterator it; 用来遍历 #include<stdio.h> #include<string.h> #include<algorithm> #include<iostream&g

hdu 4022 Bombing

Bombing Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 2650    Accepted Submission(s): 990 Problem Description It’s a cruel war which killed millions of people and ruined series of cities. In o

HDU 3080 The plan of city rebuild(prim和kruskal)

The plan of city rebuild Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 616    Accepted Submission(s): 215 Problem Description News comes!~City W will be rebuilt with the expectation to become

HDU 3080 The plan of city rebuild(除点最小生成树)

题意  一个城市原来有l个村庄 e1条道路  又增加了n个村庄 e2条道路  后来后销毁了m个村庄  与m相连的道路也销毁了  求使所有未销毁村庄相互连通最小花费  不能连通输出what a pity! 还是很裸的最小生成树  把销毁掉的标记下  然后prim咯  结果是无穷大就是不能连通的 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N =