Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 1402 | Accepted: 747 |
Description
Input
Output
Sample Input
5 5 1 1 1 1 1 1 1 1 1 1 1 2 1 2 3 1 3 4 1 4 5 1 5 1 1 1 1 1 2 1 1 1 2 1 2 1 2 3 1 3 4 1 4 5 1 5 1 1 3 1 1 2 1 1 1 2 1 2 1 2 3 1 3 4 1 4 5 1 4 2 1 1 1 3 4 3 2 1 2 3 1 3 3 1 4 2 4 4 1 1 1 3 4 3 2 1 2 3 1 3 3 1 4 2
Sample Output
2 1 2 2 3
Source
题意:
n个城市,n-1条带权边构成一棵树。
每个城市x需要在离自己不超过D[x]的距离内有一个消防站。
消防站只能建造于城市之中。每个城市建立消防站的花费是W[x]。
问满足条件的最小花费。
(n<=1000)
解法:
因为兄弟子树之间互相关联,这个题 考虑在某个结点上 建消防站或者不建消防站 很难实施。
令dp[x][y]代表 城市x最近的消防站在城市y 。
如果y在子树x外,则y点的花费不予考虑,否则要考虑。这么做是为了方便树形dp解题的一般思路,即先考虑
子树再汇总子树信息来考虑根结点。
因为y在子树x内,可以看作是过去的,如果在子树x外,可以看作是未来的。
首先假如母结点为x,儿子为y1,y2,...,yn。
那么假如x依赖于其子树中但不为x的结点,比如说是y1子树中的k1。
那么dp[x][k1]= dp[y1][k1]+ min( dp[y2][k1] , min{dp[y2][k2]} (k2在子树y2内) )+...
假如x依赖于子树x外某点,比如上方的某结点k。
那么dp[x][k]= min(dp[y1][k], min{dp[y1][k1]} (k1在子树y1内) ) + ...
假如x依赖于x自身,就是说在x点建立消防站。
那么dp[x][k]=W[x]+ min(dp[y1][x], min{dp[y1][k1]} (k1在子树y1内) ) + ...
这么做完全是因为一点 :充分利用了从某点x出发走出子树x必须经过它的父节点fa。
不管是到达 兄弟结点子树内一点 或者是 父结点 或 父结点子树外的点。
min{dp[y1][k1]} (k1在子树y1内) 可以存到 best[y1]中。
综上所述:这个题目是树形dp再加上了一点暴力搜索的成分在里面。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
typedef long long ll;
typedef pair pii;
const int INF =0x3f3f3f3f;
const int maxn=1000 ;
int n,x,y,w;
int W[maxn+10],D[maxn+10];
int dp[maxn+10][maxn+10];
int pre[maxn+10],best[maxn+10];
struct Edge
{
int to,w;
Edge(){}
Edge(int to,int w):to(to),w(w){}
};
vector G[maxn+10];
void findFireStation(int from,int nei,int x,int fa,int dis)
{
if(nei==pre[from])//上方
{
dp[from][x]=0;
for(int i=0;iD[from]) continue;
findFireStation(from,nei,y,x,dis+w);
}
}
void dfs(int x,int fa)
{
pre[x]=fa;
for(int i=0;i