有n个城市,每两个城市只有一条路连接,(所以可以当成是一颗树)。现在要建设一些防火站,使每个城市都可以被覆盖。每个城市的属性是:在本城市建防火站的价钱和不在本城市建设的话,所依赖的别的防火站的最长距离。然后是n-1条路,和这条路的长度。现在问在覆盖所有城市的前提下的最少价格。
很难的一道题,但是很巧妙.思维分好几个步骤:首先是题意的放松条件,我们不去追求真正的最近,因为兄弟节点会干扰. 很巧妙,题目中只要有一个<=d的位置的消防站就好了,并不需要一定是最近的.之后,关键是我们开dp[i][j],i为根,然后i强制因为j的消防站可以,那么对于i的子树v,v一种选择是自己内部解决,另一种选择是v的外部,那么v外部是谁呢?我们现在强制,如果v的父亲i是j的话,那么v如果去外面一定也要是j.这一点很简单:对于v来说如果有一个k比j更好,那么i为什么不用k呢?就是说k对于i和对于v并不会产生矛盾,因为都是先到了i之后再走一段距离,那么这点距离同时都很小,对于i和v都会很好.因此我们有一个这样的限制:如果i选的是j,那么他的儿子v不用自己内部解决的话一定是用的j解决的,如果不能解决,那么说明dp[i][j]不行.而且j要全部枚举1到n,因为i可以依赖i,可以依赖i外部的,可以依赖i内部的.
对论文的理解.首先克服最近的消防站,是一个大的基础条件.之后怎么解决兄弟间的问题?发现一个新性质:父亲用j,那么儿子们出去用都用j就可以是最好的.而且每一次的j可以是1到n任意一个.这样如果用兄弟的更好,那么自动就会去用兄弟的,并且此时父亲一定也是用兄弟的不错.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 1e3 +100;
const int INF = 1e9 + 10;
int n;
int dist[maxn][maxn];
int dp[maxn][maxn];
int d[maxn], w[maxn];
int vis[maxn];
int f[maxn];
struct edge
{
int to, weight;
};
vector G[maxn];//代码很简单
void dfs_dist(int root, int u, int l)//初始化出来dist,以后好用
{
vis[u] = 1;
dist[root][u] = l;
REP(i, 0, G[u].size())
{
int v = G[u][i].to;
int len = G[u][i].weight;
if(!vis[v])
{
dfs_dist(root, v, l + len);
}
}
}
void dfs_f(int root, int u, int fa)
{
f[root] = min(f[root], dp[root][u]);
REP(i, 0, G[u].size())
{
int v = G[u][i].to;
if(v!=fa)
{
dfs_f(root, v, u);
}
}
}
void dfs(int u, int fa)
{
//vis[u] = 1;
REP(i, 0, G[u].size())//先解决下面的子树的
{
int v = G[u][i].to;
//int len = G[u][i].weight;
if(v!=fa)
{
dfs(v, u);
}
}
for(int i = 1;i <= n;i++)//枚举u依赖i
{
dp[u][i] = 0;
if(dist[u][i] > d[u])//不行.
{
dp[u][i] = INF;
}
else
{
dp[u][i] = w[i];//可以,就去用
REP(j, 0, G[u].size())
{
int v = G[u][j].to;
//int len = G[u][j].weight;
if(v!=fa)
{
int tmp = min(dp[v][i] - w[i], f[v]);//这个是三种情况的综合.因为有限制,所以特别好写
if(tmp >= INF - 20000)//小细节
{
dp[u][i] = INF;
break;
}
else
{
dp[u][i] += tmp;
}
}
}
}
}
f[u] = INF;
dfs_f(u, u, fa);
}
void solve()
{
for(int i = 1;i <= n;i++)
{
CLR(vis);
dfs_dist(i, i, 0);
}
// for(int i = 1;i <= n;i++)
// {
// for(int j = 1;j <= n;j++)
// {
// printf("%d %d ---- %d\n", i, j, dist[i][j]);
// }
// }
//CLR(vis);
dfs(1, 0);
printf("%d\n", f[1]);
}
int main()
{
//freopen("2Bin.txt", "r", stdin);
//freopen("3Bout.txt", "w", stdout);
int ncase;
scanf("%d", &ncase);
while(ncase--)
{
scanf("%d", &n);
REP_D(i, 1, n)
{
scanf("%d", &w[i]);
}
REP_D(i, 1, n)
{
scanf("%d", &d[i]);
}
REP_D(i, 1, n)
{
G[i].clear();
}
REP_D(i, 1, n-1)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge t;
t.to = b;
t.weight = c;
G[a].push_back(t);
t.to = a;
G[b].push_back(t);
}
solve();
}
return 0;
}