树形dp(C - Choosing Capital for Treeland CodeForces - 219D )
题目链接:https://cn.vjudge.net/contest/277955#problem/C
题目大意:输入n,代表有n个城市,然后再输入n-1条有向边,然后让你找出一个改变边数的最小值,使得某个城市能够到达剩余的所有城市,然后问这样的城市有多少个,并且输出这些城市的编号。
具体思路:我们首先按照题目给的条件建好边,然后树就建好了,对于当前的某个节点,如果这个点要是能够到达剩余的所有城市,从这个节点往上的话,这个节点连接的父亲节点的这条边应该是是从子节点到父节点的。从这个节点往下的话,这个节点往下的话,他所连接的子节点应该是往下的,具体思路就来了。
用dp[i][0]代表当前的节点往下连接他的子树所需的最小的改变的边的数目。dp[i][1]代表的是当前的子节点往上连接他的父亲节点所需的改变最小的边数。
第二种情况,dp[rt][0]+=dp[soon][0];
第一种情况,dp[soon][1]+=dp[rt][1]+dp[rt][0]-edge[i].cost-dp[to][0]+(edge[i].cost==1?0:1).
AC代码:
1 #include<iostream> 2 #include<cmath> 3 #include<stack> 4 #include<stdio.h> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #include<cstring> 9 using namespace std; 10 # define inf 0x3f3f3f3f 11 # define ll long long 12 const int maxn = 4e5+100; 13 struct node 14 { 15 int nex; 16 int to; 17 int cost; 18 } edge[maxn]; 19 int num,head[maxn],dp[maxn][3],father[maxn]; 20 int sto[maxn]; 21 void init() 22 { 23 num=0; 24 memset(head,-1,sizeof(head)); 25 memset(dp,0,sizeof(dp)); 26 } 27 void addedge(int fr,int to,int cost) 28 { 29 edge[num].to=to; 30 edge[num].nex=head[fr]; 31 edge[num].cost=cost; 32 head[fr]=num++; 33 } 34 void dfs1(int fr,int rt) 35 { 36 for(int i=head[fr]; i!=-1; i=edge[i].nex) 37 { 38 int to=edge[i].to; 39 if(to==rt) 40 continue; 41 dfs1(to,fr); 42 dp[fr][0]+=dp[to][0]+edge[i].cost; 43 } 44 } 45 void dfs2(int fr,int rt) 46 { 47 for(int i=head[fr]; i!=-1; i=edge[i].nex) 48 { 49 int to=edge[i].to; 50 if(to==rt) 51 continue; 52 dp[to][1]+=dp[fr][1]+dp[fr][0]-dp[to][0]+(edge[i].cost==1?0:1)-edge[i].cost; 53 dfs2(to,fr); 54 } 55 } 56 int main() 57 { 58 init(); 59 int n; 60 scanf("%d",&n); 61 int t1,t2; 62 for(int i=1; i<=n-1; i++) 63 { 64 scanf("%d %d",&t1,&t2); 65 addedge(t1,t2,0); 66 addedge(t2,t1,1); 67 } 68 dfs1(1,-1); 69 dfs2(1,-1); 70 int minn=inf; 71 for(int i=1; i<=n; i++) 72 { 73 minn=min(minn,dp[i][0]+dp[i][1]); 74 } 75 printf("%d\n",minn); 76 int num=0; 77 for(int i=1; i<=n; i++) 78 { 79 if(dp[i][0]+dp[i][1]==minn) 80 { 81 sto[++num]=i; 82 } 83 } 84 sort(sto+1,sto+num+1); 85 for(int i=1; i<=num; i++) 86 { 87 if(i==1) 88 printf("%d",sto[i]); 89 else 90 printf(" %d",sto[i]); 91 } 92 printf("\n"); 93 return 0; 94 } 95