灰色的果實
問題描述
樹爲灰色果實之樹,不定時會長出灰色果實。貿然接近果實只會使得自己受其迷惑最後神經錯亂而
渾渾噩噩不得終日,與死人無異。你的目標是成功到達樹的頂端,砍下灰色果實的靈脈。
爲了能夠免除灰色果實的影響,你需要在灰色果實力量微弱時在樹的各個點
設置若干個保護點,保護點內燃燒着鎮定人心的香,以此來抵禦灰色果實的精神
襲擊。一個點必須在 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;
}