题意:给定一棵树,然后每次可以操作节点,使得节点和周围节点的状态都翻转,问是否能使得所有节点都为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; }
时间: 2024-10-24 17:53:24