BSOJ: 1625 【USACO 2002 February Green】重建道路

来源:互联网 发布:隐藏式床设计 知乎 编辑:程序博客网 时间:2024/05/13 16:28

Description
  一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场。由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟一的。因此,牧场运输系统可以被构建成一棵树。John想要知道另一次地震会造成多严重的破坏。有些道路一旦被毁坏,就会使一棵含有P(1≤P≤N)个牲口棚的子树和剩余的牲口棚分离,John想知道这些道路的最小数目。
Input
  第1行:2个整数,N和P
  第2..N行:每行2个整数I和J,表示节点I是节点J的父节点。
Output
  单独一行,包含一旦被破坏将分离出恰含P个节点的子树的道路的最小数目。
Sample Input
11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11
Sample Output
2
题目有很多翻译的版本,
这个翻译不是很好理解。
具体来说,
就是在一棵树上,
断掉一些边,
使分离出的子树至少有一个节点数为P。
怎么办呢?
很自然想到树形DP。
F[i][j],表示以i为根的子树中断边得到至少一个以j为节点数的子树的最少断边数量。
是不是很长?先慢慢看懂。
然后状态转移方程为:
F[i][j]=min(F[p][k]+F[i][jk]2){pi}
初始化F[i][1]=
然后有一个细节要注意:
在子树的信息计算出来后:
倒着循环j,不然之前计算的结果会影响后面的答案。
更多细节请仔细品味代码:

#include<cstdio>#include<iostream>#include<cmath>#include<cstdlib>#include<ctime>#include<cstring>#include<algorithm>#include<queue>#include<map>using namespace std;struct node {    int to;    int next;}w[2000];int tot[2000];int h[2000];int F[2000][2000];int cnt=1;int n,m;void AddEdge(int x,int y){    cnt++;    w[cnt].to=y;    w[cnt].next=h[x];    h[x]=cnt;}int  Dfs(int v,int fa){    F[v][1]=tot[v]; if(v!=1)F[v][1]++;    for(int i=2;i<=m;i++)F[v][i]=0x7ffffff;    for(int i=h[v];i;i=w[i].next){        int y=w[i].to;        if(y!=fa){            Dfs(y,v);            for(int j=m;j>1;j--){                for(int k=1;k<j;k++){                    F[v][j]=min(F[v][j],F[y][k]+F[v][j-k]-2);                }            }        }    }}int main(){    scanf("%d%d",&n,&m);    int x,y;    for(int i=2;i<=n;i++)tot[i]=-1;    for(int i=1;i<n;i++){        scanf("%d%d",&x,&y);        tot[x]++;        tot[y]++;        AddEdge(x,y);        AddEdge(y,x);    }    Dfs(1,0);    int Ans=0x7fffffff;    for(int i=1;i<=n;i++){        Ans=min(Ans,F[i][m]);    }    cout<<Ans;    return 0;}
2 0
原创粉丝点击