[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 }