题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714
题意:给你一棵树,,其中每去掉一条边或加一条边的代价均为1,让你求出将其变成一个圆的最小代价。
分析:由于该树要形成一个圆,所以对于分支大于等于2的子树,必须把它断开形成一条链,最后再连接起来。
定义N为1000010时不断超时,定义N为2000010时却1357ms,hdu这破oj真是让人无语。。。
#pragma comment(linker,"/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 1000000007 #define inf 0x3f3f3f3f #define N 2000010 #define FILL(a,b) (memset(a,b,sizeof(a))) using namespace std; struct edge { int next,v; edge(){} edge(int v,int next):v(v),next(next){} }e[N*2]; int head[N],tot; int sum,n; void addedge(int u,int v) { e[tot]=edge(v,head[u]); head[u]=tot++; } int dfs(int u,int fa) { int tmp=0; //计算分支数,大于等于2时有分支。 for(int i=head[u];~i;i=e[i].next) { int v=e[i].v; if(v==fa)continue; tmp+=dfs(v,u); } if(tmp>=2) { if(u==1)sum+=2*(tmp-2); //如果是根节点的话,那么其有两条边在同一分支上。 else sum+=2*(tmp-1);//否则就是只能选择一条边在一个分支上 return 0; } return 1; } int main() { int u,v,T; scanf("%d",&T); while(T--) { scanf("%d",&n); tot=0;sum=0; memset(head,-1,sizeof(head)); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1,-1); printf("%d\n",sum+1); } }
时间: 2024-10-12 22:05:11