UVA1220树上的dp(基本)

来源:互联网 发布:吃喝玩乐哪个软件好 编辑:程序博客网 时间:2024/05/18 00:44

这题做的真是心力憔悴,主要还是对dfs的不熟悉吧。

主要思路:对于每一个节点,有选择和不选择两种情况。

如果是不选择,则它的儿子可以是不选择和选择,取最大值,即 ∑max(d[v][0],d[v][1]);(v为u的子节点);

如果选择,则它的儿子不能选择即,∑d[v][0]+1(加1为加上父节点)。

然后最后求最大值。

不过这题还有一个地方就在于要判断是不是唯一路径。所以 还需要加一个judge[u][i]来做判断。(judge[u][0]==true表示不拿该节点,路径不唯一。为false则表示唯一)。(这个思路非常重要)

这个题还有一个总结出来的小技巧:用map对节点名是字符串进行编号,这样放入vector就方便很多了。


递归版本(效率低很多,但也能AC。。不推荐):

#include<cstdio>#include<map>#include<string>#include<iostream>#include<vector>#include<algorithm>#include<cstring>using namespace std;const int maxn=300;string temp,namef,names,out;///用一个map存储该节点的数字代号,v[i][j]表示第i个节点的第j个儿子int n,cnt,judge[maxn][2];int dp(int st,int t,vector<int> edge[]){    if(!edge[st].size()){         if(t==0)            return 0;        else            return 1;    }    int ans=0;    if(t==1){    for(int i=0;i<edge[st].size();i++){        ans+=dp(edge[st][i],0,edge);        if(judge[edge[st][i]][0])            judge[st][1]=true;    }        return ans+1;    }    if(t==0){    for(int i=0;i<edge[st].size();i++){        int m1=dp(edge[st][i],0,edge);        int m2=dp(edge[st][i],1,edge);        if(m1>m2){            if(judge[edge[st][i]][0])                judge[st][0]=true;            ans+=m1;        }        else if(m2>m1){            if(judge[edge[st][i]][1])                judge[st][0]=true;            ans+=m2;        }        else if(m1==m2){            judge[st][0]=true;            ans+=m1;        }        //ans+=max(m1,m2);    }        return ans;    }}int main(){ //freopen("out.txt", "w", stdout);//参数分别是,输出的文件的文件名,w是write(写),stdout(输出),    while(scanf("%d",&n)!=EOF){        if(n==0)             break;        map<string,int> id;        vector<int> edge[maxn];        memset(judge,0,sizeof(judge));        cnt=1;        cin>>temp;        for(int i=0;i<n-1;i++){            cin>>names;            cin>>namef;            if(!(id[namef]>=1&&id[namef]<=n)){               id[namef]=cnt++;            }            if(!(id[names]>=1&&id[names]<=n)){               id[names]=cnt++;            }            int u=id[namef];            int v=id[names];            edge[u].push_back(v);        }        //        int st=id[temp];        int ans1=dp(st,0,edge);        int ans2=dp(st,1,edge);        if(ans1 == ans2)  printf("%d No\n", ans1);//判断谁在数更大        else if(ans1 > ans2)  printf("%d %s\n", ans1, judge[st][0] ? "No" : "Yes");        else  printf("%d %s\n", ans2, judge[st][1] ? "No" : "Yes");    }    return 0;}


记忆化搜索(极力推荐)

#include<cstdio>#include<map>#include<string>#include<iostream>#include<vector>#include<algorithm>#include<cstring>using namespace std;const int maxn=300;string temp,namef,names,out;///用一个map存储该节点的数字代号,v[i][j]表示第i个节点的第j个儿子int n,cnt,judge[maxn][2],d[maxn][maxn];void dfs(int st,vector<int> edge[]){    if(!edge[st].size()){        d[st][1]=1;        d[st][0]=0;        return;    }    for(int i=0;i<edge[st].size();i++){        int son=edge[st][i];        dfs(son,edge);        d[st][1]+=d[son][0];        if(judge[son][0])            judge[st][1]=true;///拿了父节点,没拿子节点的情况        if(d[son][1]>d[son][0]){///不拿父节点,子节点随意            d[st][0]+=d[son][1];            if(judge[son][1])                judge[st][0]=true;        }        else if(d[son][1]<d[son][0]){            d[st][0]+=d[son][0];            if(judge[son][0])                judge[st][0]=true;        }        else{            judge[st][0]=true;            d[st][0]+=d[son][1];        }    }    d[st][1]++;}int main(){ //freopen("out.txt", "w", stdout);//参数分别是,输出的文件的文件名,w是write(写),stdout(输出),    while(scanf("%d",&n)!=EOF){        if(n==0)             break;        map<string,int> id;        vector<int> edge[maxn];        memset(judge,0,sizeof(judge));        memset(d,0,sizeof(d));        cnt=1;        cin>>temp;        for(int i=0;i<n-1;i++){            cin>>names;            cin>>namef;            if(!(id[namef]>=1&&id[namef]<=n)){               id[namef]=cnt++;            }            if(!(id[names]>=1&&id[names]<=n)){               id[names]=cnt++;            }            int u=id[namef];            int v=id[names];            edge[u].push_back(v);        }        int st;        if(n==1){          st=1;        }        else st=id[temp];        dfs(st,edge);        //cout<<ans1<<" "<<ans2<<endl;        //cout<<d[1][0]<<" "<<d[1][1]<<endl;        if(d[st][0] == d[st][1])  printf("%d No\n", d[st][0]);//判断谁在数更大        else if(d[st][0] > d[st][1])  printf("%d %s\n",d[st][0], judge[st][0] ? "No" : "Yes");        else  printf("%d %s\n", d[st][1], judge[st][1] ? "No" : "Yes");    }    return 0;}



原创粉丝点击