灰色的果实
问题描述
树为灰色果实之树,不定时会长出灰色果实。贸然接近果实只会使得自己受其迷惑最后神经错乱而
浑浑噩噩不得终日,与死人无异。你的目标是成功到达树的顶端,砍下灰色果实的灵脉。
为了能够免除灰色果实的影响,你需要在灰色果实力量微弱时在树的各个点
设置若干个保护点,保护点内燃烧着镇定人心的香,以此来抵御灰色果实的精神
袭击。一个点必须在 lim[i]距离以内有保护点才能收到保护。而且,由于在树上
作业,地形十分崎岖,使得不同点设置保护点的作业时间 time[i]不同。
谋求最大的效率,请求出保护点笼罩整棵树所需的最短作业时间。
输入格式
第一行一个整数 n 表示树的初始节点数。
第二行 n 个整数 time[i] ,表示此点设置保护点的作业时间。
第三行 n 个整数 lim[i] ,表示点受到保护的限制距离。
第四行到第 n+3 行为树的初始边,有三个整数 x,y,z,代表 x 到 y 有一
条长度为 z 的枝条。
输出格式
一个数为保护点笼罩整棵树所需的最短作业时间。
样例输入(input.txt)
Sample1 Sample2
5
1 1 1 1 1
1 1 1 1 1
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
样例输出(output.txt)
Sample1 Sample2
2 2
数据范围
数据点 限制 其它限制
1
n≤20
边权≤150
保护所修建费用≤1000
这些都不重要
2
3
4
5
6
7
n≤100
8
9
10
11
n≤2000
12
13
14
15
16
17
18
19
20
注:[题意] 若有不懂的,可以理解为在 n 个点中设置若干个特殊点,使得特殊点保护
整棵树。
[答案] 答案保证在 int 范围之内。
30分暴力
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
int n,num,ans,HA,ha;
int dis[2005][2005];
bool flag[2005],f[2005];
int tim[2005],lim[2005];
void dfs(int x,int zhi){if (zhi>=ans) return;if (zhi>1000) return;if (x>n){for (int i=1;i<=n;++i) flag[i]=true;int t=0;for (int i=1;i<=n;++i)if (f[i]==1){if (flag[i]){flag[i]=false;++t;}for (int j=1;j<=n;++j)if (flag[j]&&dis[i][j]<=lim[j]){flag[j]=false;++t;}}if (t==n) ans=min(ans,zhi);++HA;return;}f[x]=1;dfs(x+1,zhi+tim[x]);f[x]=0;dfs(x+1,zhi);
}
int main(){scanf("%d",&n);num=0;for (int i=1;i<=n;++i) scanf("%d",&tim[i]);for (int i=1;i<=n;++i) scanf("%d",&lim[i]);for (int i=1;i<=n;++i) f[i]=0;for (int i=1;i<=n;++i)for (int j=1;j<=n;++j) dis[i][j]=1<<29;for (int i=1;i<n;++i){int u,v,z;scanf("%d%d%d",&u,&v,&z);dis[u][v]=z;dis[v][u]=z;}for (int k=1;k<=n;++k)for (int i=1;i<=n;++i)if (i!=k) for (int j=1;j<=n;++j)if (k!=j&&i!=j)dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);ans=1<<29;dfs(1,0);printf("%d\n",ans);return 0;
}
正解
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int vet[4010],val[4010],Next[4010];
int hed[4010],vis[4010];
int dis[4010][4010],dp[4010][4010];
int tim[4010],lim[4010],bst[4010];
int num;
int n;
void add(int u,int v,int z){++num;vet[num]=v;val[num]=z;Next[num]=hed[u];hed[u]=num;
}void dfs(int x,int dis[]){queue<int> q;q.push(x);vis[x]=x;dis[x]=0;while (!q.empty()){int u=q.front();q.pop();for (int i=hed[u];i!=-1;i=Next[i]){int v=vet[i],z=val[i];if (vis[v]!=x){vis[v]=x;dis[v]=dis[u]+z;q.push(v);}}}
}
void check(int x,int fa){for (int i=hed[x];i!=-1;i=Next[i]){int v=vet[i];if (v==fa) continue;check(v,x);}for (int i=1;i<=n;++i)if (dis[x][i]<=lim[x]){dp[x][i]=0;for (int j=hed[x];j!=-1;j=Next[j]){int v=vet[j];if (v==fa) continue;dp[x][i]+=min(dp[v][i]-tim[i],bst[v]);}dp[x][i]+=tim[i];bst[x]=min(bst[x],dp[x][i]);}
}
int main(){scanf("%d",&n);for (int i=1;i<=n;++i) scanf("%d",&tim[i]);for (int i=1;i<=n;++i) scanf("%d",&lim[i]);for (int i=1;i<=n;++i){hed[i]=-1;vis[i]=0;bst[i]=1<<29;for (int j=1;j<=n;++j) dp[i][j]=1<<29;}for (int i=1;i<n;++i){int u,v,z;scanf("%d%d%d",&u,&v,&z);add(u,v,z);add(v,u,z);}for (int i=1;i<=n;++i) dfs(i,dis[i]);check(1,0);printf("%d\n",bst[1]);return 0;
}