[poj3107/poj2378]Godfather/Tree Cutting树形dp

题意:求树的重心(删除该点后子树最大的最小)

解题关键:想树的结构,删去某个点后只剩下它的子树和原树-此树所形成的数,然后第一次dp求每个子树的节点个数,第二次dp求解答案即可。

此题一开始一直T,后来加了输入挂才过,第一次见卡cin+关同步的题目。

用scanf试了一下,也可以过,0.5s,看来cin关同步和scanf差距也是蛮大的。

任何时候树形dp在dfs中做两次循环都是没必要的。只要了解是先序遍历和后序遍历,在一个for中处理即可。

poj2378将改为n/2即可。

优化:循环的部分少了 最终141ms

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 typedef long long ll;
10 const int maxn=1e5+3;
11 int head[maxn],tot,n;
12 struct edge{
13     int to;
14     int nxt;
15     int w;
16 }e[maxn<<1];
17 
18 void add_edge(int u,int v,int w){
19     e[tot].to=v;
20     e[tot].w=w;
21     e[tot].nxt=head[u];
22     head[u]=tot++;
23 }
24 int dp[maxn<<2],cnt[maxn];
25 
26 void dfs(int u,int fa){
27     cnt[u]=1;
28     for(int i=head[u];i!=-1;i=e[i].nxt){
29         int v=e[i].to;
30         if(v==fa) continue;
31         dfs(v,u);
32         cnt[u]+=cnt[v];
33         dp[u]=max(dp[u],cnt[v]);
34     }
35     dp[u]=max(n-cnt[u],dp[u]);
36 }
37 inline int read(){
38     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
39     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
40     if(k=='-')x=0-x;return x;
41 }
42 int main(){
43     n=read();
44     memset(head,-1,sizeof head);
45     tot=0;
46     int a,b;
47     for(int i=0;i<n-1;i++){
48         a=read();
49         b=read();
50         add_edge(a,b,1);
51         add_edge(b,a,1);
52     }
53     dfs(1,-1);
54     int ans=inf;
55     for(int i=1;i<=n;i++){
56         ans=min(ans,dp[i]);
57     }
58     bool flag=false;
59     for(int i=1;i<=n;i++){
60         if(dp[i]==ans){
61             if(flag) printf(" ");
62             printf("%d",i);
63             flag=true;
64         }
65     }
66     printf("\n");
67     return 0;
68 }

 

一:219ms

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 typedef long long ll;
10 const int maxn=1e5+3;
11 int head[maxn],tot,n;
12 struct edge{
13     int to;
14     int nxt;
15     int w;
16 }e[maxn<<1];
17 void add_edge(int u,int v,int w){
18     e[tot].to=v;
19     e[tot].w=w;
20     e[tot].nxt=head[u];
21     head[u]=tot++;
22 }
23 int dp[maxn<<2],cnt[maxn];
24 void dfs(int u,int fa){
25     cnt[u]=1;
26     for(int i=head[u];i!=-1;i=e[i].nxt){
27         int v=e[i].to;
28         if(v==fa) continue;
29         dfs(v,u);
30         cnt[u]+=cnt[v];
31     }
32     dp[u]=n-cnt[u];
33     for(int i=head[u];i!=-1;i=e[i].nxt){
34         int v=e[i].to;
35         if(v==fa) continue;
36         dp[u]=max(dp[u],cnt[v]);
37     }
38 }
39 
40 inline int read(){
41     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
42     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
43     if(k=='-')x=0-x;return x;
44 }
45 int main(){
46     //ios::sync_with_stdio(0);
47     //cin.tie(0);
48     //cout.tie(0);
49     n=read();
50     memset(head,-1,sizeof head);
51     tot=0;
52     int a,b;
53     for(int i=0;i<n-1;i++){
54         //scanf("%d%d",&a,&b);
55         //cin>>a>>b;
56         a=read();
57         b=read();
58         add_edge(a,b,1);
59         add_edge(b,a,1);
60     }
61     dfs(1,-1);
62     int ans=inf;
63     for(int i=1;i<=n;i++){
64         ans=min(ans,dp[i]);
65     }
66     bool flag=false;
67     for(int i=1;i<=n;i++){
68         if(dp[i]==ans){
69             if(flag) printf(" ");
70             printf("%d",i);
71             flag=true;
72         }
73     }
74     printf("\n");
75     return 0;
76 }

 两个dfs分开的形式,练习一下。读入挂将*10变为(x<<3)+(x<<1),变为188ms了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 typedef long long ll;
10 const int maxn=1e5+3;
11 int head[maxn],tot,n;
12 struct edge{
13     int to;
14     int nxt;
15     int w;
16 }e[maxn<<1];
17 
18 void add_edge(int u,int v,int w){
19     e[tot].to=v;
20     e[tot].w=w;
21     e[tot].nxt=head[u];
22     head[u]=tot++;
23 }
24 int dp[maxn<<2],cnt[maxn];
25 
26 void dfs(int u,int fa){
27     cnt[u]=1;
28     for(int i=head[u];i!=-1;i=e[i].nxt){
29         int v=e[i].to;
30         if(v==fa) continue;
31         dfs(v,u);
32         cnt[u]+=cnt[v];
33     }
34 }
35 
36 void dfs2(int u,int fa){    
37     dp[u]=n-cnt[u];
38     for(int i=head[u];i!=-1;i=e[i].nxt){
39         int v=e[i].to;
40         if(v==fa) continue;
41         dfs2(v,u);
42         dp[u]=max(dp[u],cnt[v]);
43     }
44 }
45 
46 inline int read(){
47     char k=0;char ls;ls=getchar();for(;ls<'0'||ls>'9';k=ls,ls=getchar());
48     int x=0;for(;ls>='0'&&ls<='9';ls=getchar())x=(x<<3)+(x<<1)+ls-'0';
49     if(k=='-')x=0-x;return x;
50 }
51 int main(){
52     //ios::sync_with_stdio(0);
53     //cin.tie(0);
54     //cout.tie(0);
55     n=read();
56     memset(head,-1,sizeof head);
57     tot=0;
58     int a,b;
59     for(int i=0;i<n-1;i++){
60         //scanf("%d%d",&a,&b);
61         //cin>>a>>b;
62         a=read();
63         b=read();
64         add_edge(a,b,1);
65         add_edge(b,a,1);
66     }
67     dfs(1,-1);
68     dfs2(1,-1);
69     int ans=inf;
70     for(int i=1;i<=n;i++){
71         ans=min(ans,dp[i]);
72     }
73     bool flag=false;
74     for(int i=1;i<=n;i++){
75         if(dp[i]==ans){
76             if(flag) printf(" ");
77             printf("%d",i);
78             flag=true;
79         }
80     }
81     printf("\n");
82     return 0;
83 }

 

posted @ 2017-08-23 18:08  Elpsywk  阅读(173)  评论(0编辑  收藏  举报