思路:
定理:叶子节点的sg值为0,中间节点的sg值为它的所有子节点的sg值加1后的异或和
这样写个dfs就可以很轻松的求解,我wa了两发,是因为建树的时候出错了,只建了单向的,比如说他给你的点对是(2,5)但实际上2是5的孩子,这样的话我们建(2,5)不就建错了,应该(5,2),所以我们加边的时候应该加双向边,dfs的时候设一个父节点,不让其反向走就可以了~
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
#include<string>
#include<cstring>
#define ll long long
using namespace std;
const int N=105;
struct pro{int to,next;};
pro edge[2*N];
int head[N],cnt;
void addEdge(int from,int to){
edge[cnt].to=to;
edge[cnt].next=head[from];
head[from]=cnt++;
}
int get_sg(int x,int pre){
int res=0;
for(int i=head[x];i!=-1;i=edge[i].next){
int dot=edge[i].to;
if(dot==pre)continue;
res^=(1+get_sg(dot,x));
}
return res;
}
void init(){
memset(head,-1,sizeof(head));
memset(edge,0,sizeof(edge));
cnt=0;
}
int main(){
int n,m,a,b;
while(scanf("%d",&n)!=EOF){//n棵树
int ans=0,flag=0;
while(n--){
scanf("%d",&m);//第i棵数有m个点
init();
for(int j=1;j<m;j++){
scanf("%d%d",&a,&b);
addEdge(a,b);
addEdge(b,a);
}
int t1=get_sg(1,0);
ans^=t1;
if(t1>1)flag=1;
}
if((ans&&flag)||(!ans&&!flag))printf("PP\n");
else printf("QQ\n");
}
}