100道动态规划——36 UVA 1220 Party at Hali-Bula 树形DP 最大独立集 思考欠妥

        题目的地址是:https://uva.onlinejudge.org/external/12/1220.pdf

        pdf不是很好放上来就只给出链接了

        好吧,这道题目我觉得我应该是可以做出来的,但是在思考上出了问题,还是需要多做一些题目来提升感觉

        首先比较显然的地方是,这道题目应该是说求一个树的最大独立集,然后在加上一点的就是求最大独立集是否是唯一的

        定义状态dp[i][k]表示目前走到第i个点,k表示是否选择该点的最大可选点数,此外还需要一个辅助数组f[i][k]表示在该点的取法是否唯一

        因此状态转移方程就有两个,第一个对应着选择该点的情况,也就是

        dp[i][1]=sum(dp[j][0]) 其中j是i的儿子,f[i][1]&=f[j][0],这个就代表着假若有一个儿子不选的最大点数的方案不唯一的话,那么选择该点的最大方案数也不唯一

        第二个对应着不选择该点的情况

        dp[i][0]=sum(max(dp[j][1],dp[j][0]),因为该点不选,所以对于每一个子节点,都可以选或者不选,关于f的更新就是假若某一个子节点dp[j][0]==dp[j][1]或者是dp[j][0]>dp[j][1]&&dp[j][0]的取法不唯一或者是dp[j][0]<dp[j][1]&&dp[j][1]的取法不唯一,那么此时这一点的取法也是不唯一的

        然后记忆化搜索一遍就好

        其实仔细思考一下应该是能做的........

        PS:本来想直接cout答案,但是不行,因为cout的表达式计算是从右向左进行的,因此会计算yes或no,后计算dfs...代码里有注释

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <map>

using namespace std;
const int maxm=210;

struct Edge{
    int nt,v;
    explicit Edge(int a=0,int b=0):nt(a),v(b){}
}edge[maxm];

map<string,int> ma;
string str1,str2;
int n,fi[maxm],dp[maxm][2],f[maxm][2],ind;
inline void addeage(int x,int y){
    edge[++ind]=Edge(fi[x],y);
    fi[x]=ind;
}
int dfs(int i,int k);

int main(){
    ios_base::sync_with_stdio(false);
    while(cin>>n&&n){
        cin>>str1;
        ma.insert(make_pair(str1,ma.size()+1));
        for(int i=1;i<n;++i){
            cin>>str1>>str2;
            if(ma.find(str1)==ma.end())
                ma.insert(make_pair(str1,ma.size()+1));
            if(ma.find(str2)==ma.end())
                ma.insert(make_pair(str2,ma.size()+1));
            addeage(ma[str2],ma[str1]);
        }

        cout<<max(dfs(1,0),dfs(1,1))<<' ';
        cout<<(dp[1][0]>dp[1][1]&&f[1][0]||dp[1][0]<dp[1][1]&&f[1][1]?"Yes\n":"No\n");
        //the calculation order of cout is right to left, so it can't concatenate together in this situation.
        ma.clear();
        memset(fi,0,sizeof fi);
        ind=0;
    }
    return 0;
}

int dfs(int i,int k){
    f[i][k]=1;
    dp[i][k]=k;
    if(k){
        for(int j=fi[i];j;j=edge[j].nt){
            dp[i][k]+=dfs(edge[j].v,0);
            f[i][k]&=f[edge[j].v][0];
        }
    }else{
        for(int j=fi[i];j;j=edge[j].nt){
            dp[i][k]+=max(dfs(edge[j].v,0),dfs(edge[j].v,1));
            f[i][k]&=!(dp[edge[j].v][0]==dp[edge[j].v][1]||
                       dp[edge[j].v][0]>dp[edge[j].v][1]&&!f[edge[j].v][0]||
                       dp[edge[j].v][0]<dp[edge[j].v][1]&&!f[edge[j].v][1]);
        }
    }
    return dp[i][k];
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值