题意:给定一棵树,然后每次可以操作节点,使得节点和周围节点的状态都翻转,问是否能使得所有节点都为1
思路:树形DP, dp[n][2][2] 的状态,
表示在第n个节点的时候,值是0或1,是否翻转过, 的状态能否到达 ,状态转移注意下细节就可以了
代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 50005;
int n;
int node[N];
bool dp[N][2][2];
void scanf_(int &num)
{
char in;
bool neg=false;
while(((in=getchar()) > '9' || in<'0') && in!='-') ;
if(in=='-')
{
neg=true;
while((in=getchar()) >'9' || in<'0');
}
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
if(neg)
num=0-num;
}
struct Edge {
int u, v;
Edge() {}
Edge(int u, int v) {
this->u = u;
this->v = v;
}
} edge[N * 2];
int en = 0;
int first[N], nex[N * 2];
void add_edge(int u, int v) {
edge[en] = Edge(u, v);
nex[en] = first[u];
first[u] = en++;
}
void dfs(int u, int p) {
memset(dp[u], false, sizeof(dp[u]));
int odd1 = 0, oe1 = 0, even1 = 0, odd2 = 0, oe2 = 0, even2 = 0;
int sum = 0;
for (int i = first[u]; i + 1; i = nex[i]) {
int v = edge[i].v;
if (v == p) continue;
dfs(v, u);
if (dp[v][0][1] && dp[v][0][0]) oe1++;
else if (dp[v][0][1]) odd1++;
else if (dp[v][0][0]) even1++;
if (dp[v][1][1] && dp[v][1][0]) oe2++;
else if (dp[v][1][1]) odd2++;
else if (dp[v][1][0]) even2++;
sum++;
}
if (oe2 + odd2 + even2 == sum) {
if (oe2) dp[u][0][0] = dp[u][1][0] = true;
else {
if (odd2&1) dp[u][!node[u]][0] = true;
else dp[u][node[u]][0] = true;
}
}
if (oe1 + odd1 + even1 == sum) {
if (oe1) dp[u][0][1] = dp[u][1][1] = true;
else {
if (odd1&1) dp[u][node[u]][1] = true;
else dp[u][!node[u]][1] = true;
}
}
}
int main() {
while (~scanf("%d", &n)) {
memset(dp, false, sizeof(dp));
memset(first, -1, sizeof(first));
en = 0;
for (int i = 1; i <= n; i++)
scanf_(node[i]);
int u, v;
for (int i = 1; i <= n - 1; i++) {
scanf_(u);
scanf_(v);
add_edge(u, v);
add_edge(v, u);
}
dfs(1, 0);
if (dp[1][1][0] || dp[1][1][1]) printf("Great Cdfpysw!\n");
else printf("Poor Nanaya!\n");
}
return 0;
}