題的意思是說他本來給你一棵樹然後你刪掉或者加上一條邊的花費都是1.問你最小花費數讓它變成一個環。
出處是HDU 4714
思路其實挺簡單的。
一直搜搜到底。然後回溯的時候的當前節點度數>2(如果是成環的話肯定就是2或者小於2)就把它和父節點之間的邊砍掉。很強的一個地方也是一開始卡住的地方就是因爲是回溯回來的。所以它下面的所有應該都是散的鏈。反正不成環。又因爲對於一個點來說移動它的耗費一定是2.砍掉和再連上嘛。每次砍的時候*2就好了。至於父節點的標記數組爲什麼要-1.因爲你在處理子節點的時候已經處理過了呀。相當於父節點可以少考慮一個節點了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int siz=1000000+10;
int book[siz];
vector<int>h[siz];
int ans=0;
void dfs(int son,int father){
for(int i=0;i<h[son].size();i++){
int newson=h[son][i];
if(newson==father) continue;
dfs(newson,son);
if(book[newson]>2){
book[son]--;
ans+=(book[newson]-2)*2;
}
}
}
int main(){
int T;
freopen("2.txt","r",stdin);
freopen("2.out","w",stdout);
scanf("%d",&T);
while(T--){
int N;
ans=0;
memset(book,0,sizeof(book));
scanf("%d",&N);
for(int i=1;i<=N;i++){
h[i].clear();
}
int a,b;
for(int i=0;i<N-1;i++){
scanf("%d%d",&a,&b);
book[b]++;
book[a]++;
h[a].push_back(b);
h[b].push_back(a);
}
int root=1;
for(int i=1;i<=N;i++){
if(book[i]==1){
root=i;
break;
}
}
dfs(root,0);
printf("%d\n",ans+1);
}
return 0;
}