冰岛人
https://pintia.cn/problem-sets/994805046380707840/problems/1111914599412858887
C++版本一
題解:LCA
25分滿分題解:
1、map映射分配ID,只要給名分配就行了;
2、起源人的姓相同不算是同一個家族;
3、數據存在性別為女的節點有子節點,此時子節點作為起源人處理;
4、存在多個起源人
5、并查集路徑壓縮
6、嫡系親屬不論相隔多少代都不能結婚(LCA沒有這個問題)
7、log2()函數可能存在精度問題
/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=200000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-2; const int INF = 0x3f3f3f3f; int t,n,m,k,p,l,r,u,v; int ans,cnt,flag,temp,sum,tot; int pre[N];//并查集 bool vis[N];//DFS標記 int dep[N];//深度 int dp[N][21];//ST char str1[30],str2[30],str3[30],str4[30],fa[N][30],son[N][30]; bool sex[N];//性別 int lg[N]; map<string,int>mp,mp1;//映射 vector<int>G[N];//圖 int find(int x){return pre[x]==x?x:pre[x]=find(pre[x]);}//并查集find() void marge(int u,int v){//并查集margeint tu=find(u);int tv=find(v);if(tu!=tv){pre[tu]=tv;} } void dfs(int u){//DFSvis[u]=1;//cout<<u<<endl;for(int i=0,j=G[u].size();i<j;i++){int v=G[u][i];if(!vis[v]){dep[v]=dep[u]+1;dp[v][0]=u;dfs(v);}} } void init(){//初始化for(int i=1;i<N;i++){G[i].clear();pre[i]=i;}memset(vis,0,sizeof(vis));memset(dep,0,sizeof(dep));memset(dp,0,sizeof(dp));mp.clear(); } int LCA(int x,int y){//最近公共祖先if(dep[x]<dep[y])swap(x,y);while(dep[x]>dep[y])x=dp[x][lg[dep[x]-dep[y]]];if(x==y)return x;for(int i=lg[dep[x]]+EXP;i>=0;i--){if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0]; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);//while(t--){scanf("%d",&n);init();for(int i=1;i<=n;i++){cin>>str1>>str2;int len=strlen(str2);mp1[str1]=i;if(str2[len-1]=='m'){sex[i]=0;}else if(str2[len-1]=='f'){sex[i]=1;}else if(str2[len-1]=='n'){sex[i]=0;}else if(str2[len-1]=='r'){sex[i]=1;}strcpy(son[i],str1);strcpy(fa[i],str2);}for(int i=1;i<=n;i++){u=i;int len=strlen(fa[i]);if(fa[i][len-1]=='n'){fa[i][len-4]='\0';v=mp1[fa[i]];if(sex[v]==0){//女爸爸問題marge(u,v);G[u].push_back(v);G[v].push_back(u);}}else if(fa[i][len-1]=='r'){fa[i][len-7]='\0';v=mp1[fa[i]];if(sex[v]==0){marge(u,v);G[u].push_back(v);G[v].push_back(u);}}}for (int i = 1; i <= n; ++i)lg[i] = lg[i - 1] + (1 << lg[i - 1] + 1 == i);//log2for(int i=1;i<=n;i++){if(pre[i]==i){dfs(i);//搜圖}}for(int i=0;i<20;i++){for(int j=1;j<=n;j++){dp[j][i+1]=dp[dp[j][i]][i];//ST}}scanf("%d",&m);for(int i=1;i<=m;i++){cin>>str1>>str2>>str3>>str4;u=mp1[str1];v=mp1[str3];//名字不存在if(mp1[str1]==0||mp1[str3]==0){cout<<"NA"<<endl;continue;}//性別相同if(sex[u]==sex[v]){cout<<"Whatever"<<endl;}else{//無公共祖先if(find(u)!=find(v)){cout<<"Yes"<<endl;continue;}//最近公共祖先int lca=LCA(u,v);//cout<<lca<<" "<<u<<" "<<v<<endl;//cout<<dep[lca]<<" "<<dep[u]<<" "<<dep[v]<<endl;if(dep[u]-dep[lca]<4||dep[v]-dep[lca]<4){//五代以內cout<<"No"<<endl;}else{cout<<"Yes"<<endl;}}}//}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }C++版本二
模擬
https://blog.csdn.net/qq_40946921/article/details/88934369
#include<iostream> #include<map> #include<string> using namespace std; struct Peoson {char sex;string father; }; map<string, Peoson> people; int judge(string a, string b) {int i = 1, j;for (string A = a; !A.empty(); A = people[A].father, i++) {j = 1;for (string B = b; !B.empty(); B = people[B].father, j++) {if (i >= 5 && j >= 5) break; //雙方都超出5代之后,不需要繼續尋找(測試點6 運行超時)if (A == B && (i < 5 || j < 5)) //五代內出現共同祖先,返回false(測試點3、6答案錯誤)return 0;}}return 1; } int main() {int n, m;string str, a, b;cin.sync_with_stdio(false);cin >> n;for (int i = 0; i < n; i++) {cin >> a >> b;if (b.back() == 'n') //兒子people[a] = { 'm',b.substr(0,b.size() - 4) };else if (b.back() == 'r') //女兒people[a] = { 'f',b.substr(0, b.size() - 7) };else people[a].sex = b.back(); //其他人}cin >> m;for (int i = 0; i < m; i++) {cin >> a >> str >> b >> str; //姓氏沒有用if (people.find(a) == people.end() || people.find(b) == people.end()) printf("NA\n");else if (people[a].sex == people[b].sex) printf("Whatever\n");else printf("%s\n", judge(a, b) ? "Yes" : "No");}return 0; }C++版本三
題解:https://blog.csdn.net/weixin_43264529/article/details/88925108
樣例圖解
第一次查 10、11號節點,最近公共父節點為0號節點,0到10和11的距離均為4,成立,輸出Yes;
第二次查 14、10號節點,最近公共父節點為3號節點,3到10和11的距離均為3,不成立,輸出No;
第三次查8,6號節點,最近公共父節點為0號節點,0到8的距離均為3,0到和6的距離為2,不成立,輸出No;
第四五次查詢性別相同,輸出Whatever
第六次查詢,信息不存在,輸出NA。
記下每一個人的父節點,然后找最近公共父節點,再檢查最近公共父節點到兩個人之間的距離是否都大于3。
#include <bits/stdc++.h> using namespace std; bool judge(vector<int> &F, int s1, int s2) {int n = F.size();vector<int> count(n, 0);vector<int> dist1(n, 0);vector<int> dist2(n, 0);int t ;count[s1]++;count[s2]++;while(F[s1] != -1){t = F[s1];count[t]++;dist1[t] = dist1[s1] + 1;if(t == s2) //直系祖宗...太亂了,直接false,不加這個,會有兩個點過不去return false;s1 = t;}while(F[s2] != -1){t = F[s2];count[t]++;dist2[t] = dist2[s2] + 1;if(count[t] > 1){if(dist2[t]>=4 && dist1[t] >= 4)return true;elsereturn false;}s2 = t;}return true; } int main() {int n;cin >> n;string f1, f2;vector<bool> sex(n);vector<vector<string> > record(n);map<string, int> M; //給每個人編號vector<int> F(n, -1); //父節點編號int cnt = 0;for(int i=0;i<n;i++) //編號{cin >> f1 >> f2;M.insert(make_pair(f1, cnt));int l = f2.size();if(f2[l-1] == 'm' || f2[l-1] == 'n')sex[cnt] = 1; //男elsesex[cnt] = 0;cnt++;record[i].push_back(f1);record[i].push_back(f2);}string par;for(int i=0;i<n;i++) //找父節點{f1 = record[i][0];f2 = record[i][1];int len = f2.size();if(f2[len-1] != 'r' && f2[len-1] != 'n') //老祖宗continue;if(sex[M[f1]] == true)par = f2.substr(0, len-4);elsepar = f2.substr(0, len-7);F[M[f1]] = M[par];}int m;cin >> m;string t1,t2;for(int i=0;i<m;i++){cin >> f1 >> f2 >> t1 >> t2;if(M.find(f1) == M.end() || M.find(t1) == M.end() ){cout << "NA" << endl;continue;}if(sex[M[f1]] == sex[M[t1]]){cout << "Whatever" << endl;continue;}if(judge(F, M[f1], M[t1])){cout << "Yes" << endl;}elsecout << "No" << endl;}return 0; }24分
一個女爸爸問題
/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=200000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-2; const int INF = 0x3f3f3f3f; int t,n,m,k,p,l,r,u,v; int ans,cnt,flag,temp,sum,tot; int pre[N];//并查集 bool vis[N];//DFS標記 int dep[N];//深度 int dp[N][21];//ST char str1[30],str2[30],str3[30],str4[30],fa[N][30],son[N][30]; bool sex[N];//性別 int frist[N];//父節點 int lg[N]; map<string,int>mp;//映射 vector<int>G[N];//圖 int find(int x){return pre[x]==x?x:pre[x]=find(pre[x]);}//并查集find() void marge(int u,int v){//并查集margeint tu=find(u);int tv=find(v);if(tu!=tv){pre[tu]=tv;} } void dfs(int u){//DFSvis[u]=1;for(int i=0,j=G[u].size();i<j;i++){int v=G[u][i];if(!vis[v]){dep[v]=dep[u]+1;dp[v][0]=u;dfs(v);}} } void init(){//初始化for(int i=1;i<N;i++){G[i].clear();pre[i]=i;}memset(vis,0,sizeof(vis));memset(dep,0,sizeof(dep));memset(dp,0,sizeof(dp));cnt=0;tot=0;mp.clear(); } int LCA(int x,int y){//最近公共祖先if(dep[x]<dep[y])swap(x,y);while(dep[x]>dep[y])x=dp[x][lg[dep[x]-dep[y]]];if(x==y)return x;for(int i=lg[dep[x]]+EXP;i>=0;i--){if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0]; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);//while(t--){scanf("%d",&n);n*=2;init();for(int i=1;i<=n/2;i++){cin>>str1>>str2;int len=strlen(str2);bool sex0=0;//性別判斷if(str2[len-1]=='m'){str2[len-1]='\0';sex0=0;}else if(str2[len-1]=='f'){str2[len-1]='\0';sex0=1;}else if(str2[len-1]=='n'){str2[len-4]='\0';sex0=0;}else if(str2[len-1]=='r'){str2[len-7]='\0';sex0=1;}if(!mp[str1]){mp[str1]=++tot;}if(!mp[str2]){mp[str2]=++tot;}u=mp[str1];v=mp[str2];sex[u]=sex0;//sex[v]=0;strcpy(son[i],str1);strcpy(fa[i],str2);//cout<<str2<<v<<sex[v]<<endl;}for(int i=1;i<=n/2;i++){u=mp[son[i]];v=mp[fa[i]];frist[u]=v;if(sex[v]==0){marge(u,v);G[u].push_back(v);G[v].push_back(u);}}for (int i = 1; i <= tot; ++i)lg[i] = lg[i - 1] + (1 << lg[i - 1] + 1 == i);for(int i=1;i<=tot;i++){if(pre[i]==i){dfs(i);}}//cout<<"2"<<endl;for(int i=0;i<20;i++){for(int j=1;j<=tot;j++){dp[j][i+1]=dp[dp[j][i]][i];}}scanf("%d",&m);for(int i=1;i<=m;i++){cin>>str1>>str2>>str3>>str4;u=mp[str1];v=mp[str3];int fu=mp[str2];int fv=mp[str4];//名字不存在if(mp[str1]==0||mp[str2]==0||mp[str3]==0||mp[str4]==0||frist[u]!=fu||frist[v]!=fv){cout<<"NA"<<endl;continue;}//性別相同if(sex[u]==sex[v]){cout<<"Whatever"<<endl;}else{//無公共祖先if(find(u)!=find(v)){cout<<"Yes"<<endl;continue;}//最近公共祖先int lca=LCA(u,v);//cout<<lca<<" "<<u<<" "<<v<<endl;//cout<<dep[lca]<<" "<<dep[u]<<" "<<dep[v]<<endl;if(dep[u]-dep[lca]<4||dep[v]-dep[lca]<4){//五代以內cout<<"No"<<endl;}else{cout<<"Yes"<<endl;}}}//}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }?
22分(滿分25分)真的不會了
/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=200000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; int t,n,m,k,p,l,r,u,v; int ans,cnt,flag,temp,sum,tot; int pre[N]; bool vis[N]; int dep[N]; int dp[N][21]; char str1[30],str2[30],str3[30],str4[30]; bool sex[N]; int frist[N]; map<string,int>mp; vector<int>G[N]; int find(int x){return pre[x]==x?x:pre[x]=find(pre[x]);} void marge(int u,int v){int tu=find(u);int tv=find(v);if(tu!=tv){pre[tu]=tv;} } void dfs(int u){vis[u]=1;for(int i=0,j=G[u].size();i<j;i++){int v=G[u][i];if(!vis[v]){dep[v]=dep[u]+1;dp[v][0]=u;dfs(v);}} } void init(){for(int i=1;i<N;i++){G[i].clear();pre[i]=i;}memset(vis,0,sizeof(vis));memset(dep,0,sizeof(dep));memset(dp,0,sizeof(dp));cnt=0;tot=0;mp.clear(); } int LCA(int x,int y){if(dep[x]<dep[y])swap(x,y);//cout<<x<<" "<<dp[1][0]<<endl;while(dep[x]>dep[y])x=dp[x][(int)log2(dep[x]-dep[y])];if(x==y)return x;for(int i=log2(dep[x]);i>=0;i--){if(dp[x][i]!=dp[y][i])x=dp[x][i],y=dp[y][i];}return dp[x][0]; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);//while(t--){scanf("%d",&n);n*=2;init();for(int i=1;i<=n/2;i++){cin>>str1>>str2;int len=strlen(str2);bool sex0=0;if(str2[len-1]=='m'){str2[len-1]='\0';sex0=0;}else if(str2[len-1]=='f'){str2[len-1]='\0';sex0=1;}else if(str2[len-1]=='n'){str2[len-4]='\0';sex0=0;}else if(str2[len-1]=='r'){str2[len-7]='\0';sex0=1;}if(!mp[str1]){mp[str1]=++tot;}if(!mp[str2]){mp[str2]=++tot;}u=mp[str1];v=mp[str2];sex[u]=sex0;sex[v]=0;frist[u]=v;marge(u,v);G[u].push_back(v);G[v].push_back(u);//cout<<str2<<v<<endl;}for(int i=1;i<=n;i++){if(pre[i]==i){dfs(i);}}//cout<<"2"<<endl;for(int i=0;i<20;i++){for(int j=1;j<=n;j++){dp[j][i+1]=dp[dp[j][i]][i];}}scanf("%d",&m);for(int i=1;i<=m;i++){cin>>str1>>str2>>str3>>str4;u=mp[str1];v=mp[str3];int fu=mp[str2];int fv=mp[str4];if(mp[str1]==0||mp[str2]==0||mp[str3]==0||mp[str4]==0||frist[u]!=fu||frist[v]!=fv){cout<<"NA"<<endl;continue;}if(sex[u]==sex[v]){cout<<"Whatever"<<endl;}else{if(find(u)!=find(v)){cout<<"Yes"<<endl;continue;}int lca=LCA(u,v);//cout<<lca<<" "<<u<<" "<<v<<endl;//cout<<dep[lca]<<" "<<dep[u]<<" "<<dep[v]<<endl;if(dep[u]-dep[lca]<4||dep[v]-dep[lca]<4){cout<<"No"<<endl;}else{cout<<"Yes"<<endl;}}}//}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }?
?
總結