树形dp
题意:给出了一棵树, 这个树上的边有两种类型,一种是保护的, 另一种是不保护的。 现在想让每个点到根节点中的路线中,受保护的边至少有一半, 现在至少要改变多少条变才能达到目的, 并输出修改边的方案。
思路:这道题是如果要改变边的话那么就尽量在靠近根节点的地方修改边。
我们用一个need保存这个子树中的点要满足要求需要改变边的数目。
那么need[u] = max( (step+1)/2-have, need[v]) v是u的子节点。
然后就是建路的过程, 这个时候我犯了一个错误。 开始的时候我一直递归, 进行到修改边的数目大于等于需要的就停止。其实在进行带u,如果在u的v之间是否修路,看的不是need[u],而是v, 因为不满足u,但是可能满足v。如果满足了u,那么一定能够满足v。
AC代码:
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <algorithm> using namespace std; const int N = 200005, INF = 1<<25; struct EDGE { int v, next; int w; } edge[N*2]; int num, head[N], need[N], ans[N], step; int n; void add(int u, int v, int w) { edge[num].v = v; edge[num].w = w; edge[num].next = head[u]; head[u] = num++; } void init() { num = 0; memset(head, -1, sizeof(head)); char str[30]; int u, v; for(int i=1; i<n; i++) { scanf("%d%d%s", &u, &v, str); if(str[0] == 'a') { scanf("%s", str); add(u,v,0); add(v,u,0); } else { add(u,v,1); add(v,u,1); } } } void dfs(int u, int pre, int step, int path) { need[u] = (step+1)/2 - path; for(int i=head[u]; i!=-1; i=edge[i].next) { if(edge[i].v == pre) continue; dfs(edge[i].v, u, step+1, path+edge[i].w); need[u] = max(need[u],need[edge[i].v]); } if(need[u] < 0) need[u] = 0; } void dfs1(int u, int pre, int now) { int v; if(need[u] <= now) return; for(int i=head[u]; i!=-1; i=edge[i].next) { v = edge[i].v; if(v == pre) continue; if(now < need[v]) { if(edge[i].w == 0) { ans[step++] = i/2+1; dfs1(edge[i].v,u,now+1); } else dfs1(edge[i].v,u,now); } } } void solve() { dfs(1, -1, 0, 0); step = 0; dfs1(1,-1,0); printf("%d\n",step); sort(ans, ans+step); for(int i=0; i<step-1; i++) printf("%d ",ans[i]); if(step) printf("%d\n", ans[step-1]); } int main() { while(scanf("%d", &n) != EOF) { init(); solve(); } return 0; }


浙公网安备 33010602011771号