1、vector< int>[]存储数据 + 递归DFS+判断
(1)功夫传人
考察某一位祖师爷门下的徒子徒孙家谱:假设家谱中的每个人只有1位师傅(除了祖师爷没有师傅);每位师傅可以带很多徒弟;并且假设辈分严格有序,即祖师爷这门武功的每个第i代传人只能在第i-1代传人中拜1个师傅。我们假设已知祖师爷的功力值为Z,每向下传承一代,就会减弱r%,除非某一代弟子得道则功力乘N。
【输入样例】
10 18.0 1.00
3 2 3 5
1 9
1 4
1 7
0 7
2 6 1
1 8
0 9
0 4
0 3
【输出样例】
404
现给出师门谱系关系,要求你算出所有得道者的功力总值。
思路: 先用vector< int> []存储门派关系,double[]存储是否得到秘籍功力加倍,后DFS递归得总和。
#include <vector>
#define maxn 100001
double secret[maxn],result=0,z,r; //记录功力乘数
vector<int> info[maxn]; //记录家谱
void dfs(int num,double power){
if (secret[num]){
result+=power*secret[num];
return;
}
for (int i=0;i<info[num].size();i++) dfs(info[num][i],power*(100-r)/100);
}
int main(){
int n,k,in;
cin>>n>>z>>r;
for (int i=0;i<n;i++) secret[i]=0; //秘籍=0
for (int i=0;i<n;i++){
cin>>k;
if (k){
for (int j=0;j<k;j++){
cin>>in;
info[i].push_back(in);
}
}
else cin>>secret[i]; //乘数
}
dfs(0,z);
cout<<int(result);
return 0;
}
2、愿天下有情人终成兄妹
【输入样例】
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
【输出样例】
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No
思路: 先用vector< int>[]存储父母信息,int[]存储性别(初始化为0,男=1女=2,题目可能会给无性别的人)。记得存储父母信息时赋予性别,父母离异再婚家庭树会变化。DFS每次先初始化标记数组,判断到第4辈祖上因为同辈已占了一代。
#include <bits/stdc++.h>
#include <vector>
#define maxn 1000000
vector<int> info[maxn];//父母
int gender[maxn],visit[maxn],flag;//性别,五代标记,是否可婚
void dfs(int x,int depth){
if (depth==4) return; //判断到第4辈
for (int i=0;i<info[x].size();i++){
if (visit[info[x][i]]==0){
visit[info[x][i]]=1; //走过此亲戚
dfs(info[x][i],depth+1);//下一代
}
else flag=1;
}
return;
}
int main(){
int n,a,c,d;
cin>>n;
char b;
memset(gender,0,sizeof(gender)); //性别初始化
for (int i=0;i<n;i++){
cin>>a>>b>>c>>d;
if (b=='F') gender[a]=2;//女
else if (b=='M') gender[a]=1;//男
else continue;//不知道给的什么鬼
if (c!=-1){//有父亲
info[a].push_back(c);
gender[c]=1;
}
if (d!=-1){//有母亲
info[a].push_back(d);
gender[d]=2;
}
}
cin>>a;
for (int i=0;i<a;i++){
cin>>c>>d;
if (gender[c]==gender[d]) cout<<"Never Mind\n";
else{
memset(visit,0,sizeof(visit));
visit[c]=1,visit[d]=1;
flag=0;
dfs(c,0),dfs(d,0);
if (flag) cout<<"No\n";
else cout<<"Yes\n";
}
}
return 0;
}
3、病毒溯源*
【输入样例】
10
3 6 4 8
0
0
0
2 5 9
0
1 7
1 2
0
2 3 1
【输出样例】
4
0 4 9 1
思路: 先用vector< int>[]存储数据,用int类型加减找出没有作为变异病毒的源头(题目说保证为1个),记得每组升序则替换一定为更长序列(保证输出序列最小)。dfs时先push再dfs后pop,vector类型不仅能直接比大小,还能直接=赋值!
#include <bits/stdc++.h>
#include <algorithm>
#include <vector>
#include <map>
#define maxn 10000
vector<int> info[maxn]; //存储信息
map<int,int> have;//是否作为变异病毒
vector<int> res,t; //结果列表和暂存
int maxi=0;
void dfs(int root,int depth){
if (depth>maxi){ //更长
maxi = depth;
res = t;
}
for (int i=0;i<info[root].size();i++){
t.push_back(info[root][i]); //路径加入
dfs(info[root][i],depth+1);
t.pop_back(); //再pop出来
}
}
int main(){
//输入
int n,k,in,sum=0;
cin>>n;
for (int i=0;i<n;i++){
cin>>k;
sum += i;
for (int j=0;j<k;j++){
cin>>in;
info[i].push_back(in);
if (have.find(in)==have.end()){//非源头
sum-=in;
have[in]=1;
}
}
sort(info[i].begin(),info[i].end()); //从小到大排列则替换一定变成更长序列
}
dfs(sum,0); //从源头开始找
cout<<1+res.size()<<"\n"<<sum;
for (int i=0;i<maxi;i++) cout<<" "<<res[i];
return 0;
}