心如止水
Je n'ai pas le temps
posts - 400,comments - 130,trackbacks - 0
题目描述
农夫John的农场有n(n<=150)个牛舍,有些牛舍之间有双向道路连接,而每两个牛舍之间有且仅有一条道路(因此可以表示成一棵树)。由于任意一场地震都很可能让John的农场变得不连通,因此John希望估计一下,至少需要毁坏多少条道路才会让一个恰好有p(p<=n)个牛舍的子树脱离其他牛舍。

此题采用树型动态规划求解。
1、建树
由于一个结点可能会有多个子结点,给下面的动态规划带来不便,所以采用“左儿子右兄弟”表示法。
2、状态定义
定义d(i,j)表示在i结点上选取它的儿子或右边的兄弟或右边的兄弟的兄弟……共j个(包含自身)至少需要毁坏的道路数。
3、状态转移方程
考虑几种决策:
i结点连同所有儿子结点都舍弃不用:d(i,j)=d(R(i),j)+1;
i结点由包含k个结点的左子树和j-k-1个结点的右子树组成:d(i,j)=d(L(i),k)+d(R(i),j-k-1);
4、边界条件
为了方便处理,如果一个结点没有左儿子或右儿子(在转换之后的二叉树中),那么它的左儿子或右儿子为0号结点。
那么边界可以是:
d(0,0)=0;
d(0,i)=INF,1<=i<=n;
我觉得这种表示还是很巧妙的。
注意,即使以i结点为根的数左子树为空,也不一定毁坏一条道路就能剪掉整个左子树,因为这是转换了之后的二叉树,原树上i结点可能有众多子结点。
5、最优解
在d(L(i),p-1)+(i==root?0:1)中找最优解。因为如果i是根节点,不需要毁坏任何道路。

以下是我的代码:
#include<fstream>
#include
<string.h>
#define maxn 157
#define INF 20000007
using namespace std;
long min(long a,long b){return (a<b?a:b);}

typedef 
struct
{
    
long ls,rs;
}treenode;

long n,p,root,ans,father[maxn],d[maxn][maxn];
treenode tree[maxn];

void Insert(long u,long v)
{
    
if(!tree[u].ls)
        tree[u].ls
=v;
    
else
    {
        
long p;
        
for(p=tree[u].ls;tree[p].rs;p=tree[p].rs);
        tree[p].rs
=v;
    }
}

long dp(long i,long j)
{
    
if(d[i][j]!=-1return d[i][j];
    d[i][j]
=dp(tree[i].rs,j)+1;
    
for(long k=0;j-k-1>=0;k++)
        d[i][j]
=min(d[i][j],dp(tree[i].ls,k)+dp(tree[i].rs,j-k-1));
    
return d[i][j];
}

int main()
{
    ifstream fin(
"roads.in");ofstream fout("roads.out");
    
    memset(tree,
0,sizeof(tree));
    memset(father,
0,sizeof(father));
    fin
>>n>>p;
    
for(long i=1;i<=n-1;i++)
    {
        
long u,v;
        fin
>>u>>v;
        Insert(u,v);
        father[v]
=u;
    }
    
//  Input
    
    memset(d,
-1,sizeof(d));
    
for(long i=1;i<=n;i++)
        d[
0][i]=INF;
    d[
0][0]=0;
    
//  Init
    
    
for(long i=1;i<=n;i++)
        
if(!father[i])
            root
=i;
    
//  Find root
    
    ans
=INF;
    
for(long i=1;i<=n;i++)
      ans
=min(ans,dp(tree[i].ls,p-1)+(i==root?0:1));
    fout
<<ans<<endl;
    
//  Output
    
    fin.close();fout.close();
return 0;
}
posted on 2010-10-11 22:47 lee1r 阅读(535) 评论(0)  编辑 收藏 引用 所属分类: 题目分类:动态规划

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理