1. 程式人生 > >bzoj1912【Apio2010】patrol 巡邏

bzoj1912【Apio2010】patrol 巡邏

 


題解:

        顯然需要分類討論了,首先理解k==0即原圖時按照dfs序來說 , 每條邊至少走兩次;

        k==1,相當於可以省去dfs回溯時第二次走過某條路徑的浪費,所以答案是k==0的答案-直徑 ;

        k==2,和k==1同理,答案是k==0時的答案-兩條邊不相交的鏈的最大和,先做一次直徑,將直徑上的邊邊權都賦值為取為相反數,再做一次直徑即可;(應該邊權不只有1也是適用的吧,注意第二次的邊權有負值只能用dp求直徑)

      

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=100010;
 4 int n,k,o=2,hd[N],mx,mx1,mx2,s1[N],s2[N],dia;
 5 struct Edge{int v,nt,w;}E[N<<1];
 6 void adde(int u,int v,int w){
 7     E[o]=(Edge){v,hd[u],w};hd[u]=o++;
 8     E[o]=(Edge){u,hd[v],w};hd[v]=o++;
9 } 10 int dfs(int u,int fa){ 11 int mx1=0,mx2=0; 12 for(int i=hd[u];~i;i=E[i].nt){ 13 int v=E[i].v; 14 if(v==fa)continue; 15 int w = E[i].w + dfs(v,u); 16 if(w>mx1)mx2=mx1,s2[u]=s1[u],mx1=w,s1[u]=i; 17 else if(w>mx2)mx2=w,s2[u]=i; 18 }
19 if(mx1+mx2>dia)mx=u,dia=mx1+mx2; 20 return mx1; 21 } 22 int main(){ 23 freopen("bzoj1912.in","r",stdin); 24 freopen("bzoj1912.out","w",stdout); 25 scanf("%d%d",&n,&k); 26 memset(hd,-1,sizeof(hd)); 27 for(int i=1,u,v;i<n;i++){ 28 scanf("%d%d",&u,&v); 29 adde(u,v,1); 30 } 31 int ans=(n-1)<<1; 32 dia=0;dfs(1,0); 33 ans=ans-dia+1; 34 if(k==2){ 35 for(int i=s1[mx];i;i=s1[E[i].v])E[i].w=E[i^1].w=-1; 36 for(int i=s2[mx];i;i=s1[E[i].v])E[i].w=E[i^1].w=-1; 37 dia=0;dfs(1,0); 38 ans=ans-dia+1; 39 } 40 printf("%d\n",ans); 41 return 0; 42 }
bzoj1912