树形DP
说是树形DP,其实就是求树的最长链嘛……
K=1的时候明显是将树的最长链的两端连起来最优。
但是K=2的时候怎么搞?
考虑第一次找完树的最长链以后的影响:第一次找过的边如果第二次再走,对答案的贡献会变成-1,因为两次都选这一段的话,反而会使得这一段不得不走两次(如果只被选一次的话就可以只走一次),所以就将第一次找出的树的最长链上的边权值都改为-1。这个操作可以用链表实现(类比一下最小费用最大流的spfa实现!)
题解:http://blog.csdn.net/qpswwww/article/details/43935861
1 /************************************************************** 2 Problem: 1912 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:580 ms 7 Memory:5752 kb 8 ****************************************************************/ 9 10 //BZOJ 1912 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 #define CC(a,b) memset(a,b,sizeof(a)) 22 using namespace std; 23 inline int getint(){ 24 int v=0,sign=1; char ch=getchar(); 25 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 26 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 27 return v*sign; 28 } 29 const int N=1e5+10,INF=~0u>>2; 30 typedef long long LL; 31 /******************tamplate*********************/ 32 int head[N],to[N<<1],next[N<<1],len[N<<1],cnt=1; 33 void add(int x,int y){ 34 to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; len[cnt]=1; 35 to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt; len[cnt]=1; 36 } 37 int n,K; 38 int D,S,son1[N],son2[N]; 39 int dfs(int x,int fa){ 40 int m1=0,m2=0; 41 for(int i=head[x];i;i=next[i]) 42 if (to[i]!=fa){ 43 int nowh=dfs(to[i],x)+len[i]; 44 if (nowh>m1){m2=m1;m1=nowh;son2[x]=son1[x];son1[x]=i;} 45 else if (nowh>m2){m2=nowh; son2[x]=i;} 46 } 47 if (D<m1+m2) D=m1+m2,S=x; 48 return m1; 49 } 50 int main(){ 51 #ifndef ONLINE_JUDGE 52 freopen("1912.in","r",stdin); 53 freopen("1912.out","w",stdout); 54 #endif 55 n=getint(); K=getint(); 56 F(i,2,n){ 57 int x=getint(),y=getint(); 58 add(x,y); 59 } 60 int ans=(n-1)<<1; 61 D=0; 62 CC(son1,-1); 63 CC(son2,-1); 64 dfs(1,-1); 65 ans-=D-1; 66 if (K>1){ 67 D=0; 68 for(int i=son1[S];i!=-1;i=son1[to[i]]) len[i]=len[i^1]=-1; 69 for(int i=son2[S];i!=-1;i=son1[to[i]]) len[i]=len[i^1]=-1; 70 CC(son1,-1); 71 CC(son2,-1); 72 dfs(1,-1); 73 ans-=D-1; 74 } 75 printf("%d ",ans); 76 return 0; 77 } 78
1912: [Apio2010]patrol 巡逻
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 642 Solved: 362
[Submit][Status][Discuss]
Description
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b,
表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。
Sample Input
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
1 2
3 1
3 4
5 3
7 5
8 5
5 6
Sample Output
11
HINT
10%的数据中,n ≤ 1000, K = 1;
30%的数据中,K = 1;
80%的数据中,每个村庄相邻的村庄数不超过 25;
90%的数据中,每个村庄相邻的村庄数不超过 150;
100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。