这题做的真是心力憔悴,主要还是对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]++;///遍历完所有子节点要记得加上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;
}