题意:给一棵树,删边和加边的代价都为1,求把树变成一个圈所花的最小代价。
思路:对原树进行删边操作,直到将原树分成若干条链,然后通过在链之间添加边形成圈,由于删边和加边一一对应,且最后需要额外一条边连成圈,所以有:
最小代价=(最小链数-1)*2+1=最小链数*2-1。
令dp[i][0]表示i不和i的父亲相连,i这颗子树所形成的最少链数,dp[i][1]表示i和i的父亲相连,i这颗子树所形成的最少链数,则:
dp[i][0]=∑dp[j][0]+dp[p][1]-dp[p][0] + dp[q][1]-dp[q][0]-1
dp[i][1]=∑dp[j][0]+dp[p][1]-dp[p][0]
其中,j是i的子节点,p是满足dp[j][1]-dp[j][0]最小的j,q是满足dp[j][1]-dp[j][0]第二小的j。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define copy(a, b) memcpy(a, b, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; //#ifndef ONLINE_JUDGE void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} //#endif template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} const double PI = acos(-1.0); const int INF = 1e9 + 7; const double EPS = 1e-12; /* -------------------------------------------------------------------------------- */ const int maxn = 1e6 + 7; pii E[maxn * 2]; int SZ; int Next[maxn * 2]; int last[maxn]; int son[maxn]; void add(int u, int v) { E[SZ ++] = mp(u, v); E[SZ ++] = mp(v, u); Next[SZ - 2] = last[u]; last[u] = SZ - 2; Next[SZ - 1] = last[v]; last[v] = SZ - 1; } int vis[maxn], dp[maxn][2]; void dfs(int rt) { vis[rt] = true; int ans = 0, minv1 = INF, minv2 = INF, sum = 0, sum1 = 0, cnt = 0; for (int i = last[rt]; ~i; i = Next[i]) { int v = E[i].Y; if (!vis[v]) { dfs(v); cnt ++; sum += dp[v][0]; sum1 += dp[v][1]; int buf = dp[v][1] - dp[v][0]; if (buf < minv1) { minv2 = minv1; minv1 = buf; } else { if (buf < minv2) minv2 = buf; } } } if (cnt == 0) dp[rt][0] = dp[rt][1] = 1; else if (cnt == 1) dp[rt][0] = dp[rt][1] = sum1; else if (cnt >= 2) { dp[rt][0] = sum + minv1 + minv2 - 1; dp[rt][1] = sum + minv1; } // printf("%d: %d %d ", rt, dp[rt][0], dp[rt][1]); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T; cin >> T; while (T --) { int n; cin >> n; SZ = 0; fillchar(last, - 1); fillchar(Next, - 1); for (int i = 1; i < n; i ++) { int u, v; scanf("%d%d", &u, &v); add(u, v); } fillchar(vis, 0); dfs(1); cout << dp[1][0] * 2 - 1 << endl; } return 0; } |