灰色的果實

灰色的果實

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

Tips:lim[i]lim[i]
#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;
}

正解

DPdp[i][j]ij

bst[i]i
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章