BZOJ1912[Apio2010]patrol 巡逻
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1912
题解:嗯,这是一道很好的题。
转自:http://www.cnblogs.com/iwtwiioi/p/4126284.html
对于 k==0 的情况:
我们发现遍历一棵树最后回到原点,那么对于所有的边,我们都是走过去,再走回来。
答案 (n−1<<1)
对于 k==1 的情况
设每条边长度为1,然后树上找最长链,然后这条链走过去就不再一步步往回了,直接从链底连一条边去链顶,然后链中间连的那些点,直接走过去再走回来,它们那些边的答案是不变的。
答案 (n−1<<1)−(链长度)+1
可以证明不能减得更多啦。
z对于 k==2 的情况
设上一次的直径上的边的边长都为-1,因为再走一次会坑,然后树上找最长链。
答案 (n−1<<1)−(链1长度)+1−(链2长度)+1
可以证明不能减得更多啦。
我在这里就不贴出证明了,以免给读者养成不自己证明的惰性(其实是我这两天惰性有点大2333)
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #define maxn 100005 7 #define maxm 200005 8 int n,k,c; 9 int ans,sum,mx,tot; 10 int s1[maxm],s2[maxm]; 11 int now[maxn],pre[maxm],v[maxm],val[maxm]; 12 int read() 13 { 14 int x=0; char ch; bool bo=0; 15 while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1; 16 while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 17 if (bo) return -x; return x; 18 } 19 void ins(int a,int b,int c) 20 { 21 ++tot; pre[tot]=now[a]; now[a]=tot; v[tot]=b; val[tot]=c; 22 } 23 int dfs(int x,int fa) 24 { 25 int mx1=0,mx2=0; 26 for (int p=now[x]; p; p=pre[p]) 27 { 28 int son=v[p]; 29 if (son==fa) continue; 30 int vv=val[p]+dfs(son,x); 31 if (vv>mx1) mx2=mx1,mx1=vv,s2[x]=s1[x],s1[x]=p; 32 else if (vv>mx2) mx2=vv,s2[x]=p; 33 } 34 if (mx1+mx2>sum) sum=mx1+mx2,mx=x; 35 return mx1; 36 } 37 int main() 38 { 39 n=read(); k=read(); int c=1; 40 for (int i=1; i<n; i++) 41 { 42 int u=read(),v=read(),val=1; 43 ins(u,v,val); ins(v,u,val); 44 ans+=2*val; 45 } 46 dfs(1,0); 47 ans-=sum-1; 48 if (k==2) 49 { 50 for (int p=s1[mx]; p; p=s1[v[p]]) val[p]=-1*val[p]; 51 for (int p=s2[mx]; p; p=s1[v[p]]) val[p]=-1*val[p]; 52 sum=0; 53 dfs(1,0); ans-=sum-1; 54 } 55 printf("%d\n",ans); 56 }
注:可以想想k不等于2,而是大于2怎么做,因为某次noi模拟赛就是这道题的加强版【这道题就不给题面了,你懂得!】,k的大小不限,于是怎么做呢???有两种做法:tree dp,还有就是这个写法,但是要改一些东东,自己可以想想,自己也写写,然后可以用我程序对拍。
代码如下:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 #define maxn 2005 7 #define maxm 4005 8 using namespace std; 9 int n,k,c; 10 int ans,sum,mx,tot; 11 int s1[maxm],s2[maxm]; 12 int now[maxn],pre[maxm],v[maxm],val[maxm]; 13 bool bo[maxm]; 14 int read() 15 { 16 int x=0; char ch; bool bo=0; 17 while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1; 18 while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 19 if (bo) return -x; return x; 20 } 21 void ins(int a,int b,int c) 22 { 23 ++tot; pre[tot]=now[a]; now[a]=tot; v[tot]=b; val[tot]=c; 24 } 25 int dfs(int x,int fa) 26 { 27 int mx1=0,mx2=0; 28 for (int p=now[x]; p; p=pre[p]) 29 { 30 int son=v[p]; 31 if (son==fa) continue; 32 int vv=val[p]+dfs(son,x); 33 if (vv>mx1) mx2=mx1,mx1=vv,s2[x]=s1[x],s1[x]=p; 34 else if (vv>mx2) mx2=vv,s2[x]=p; 35 } 36 if (mx1+mx2>sum) sum=mx1+mx2,mx=x; 37 return mx1; 38 } 39 void clear() 40 { 41 for (int i=1; i<=maxn; i++) now[i]=s1[i]=s2[i]=0; 42 ans=0; tot=0; 43 } 44 int main() 45 { 46 //freopen("data.in","r",stdin); 47 //freopen("wrong.out","w",stdout); 48 while (scanf("%d\n",&n)!=EOF) 49 { 50 clear(); 51 k=read(); int c=read(); 52 for (int i=1; i<n; i++) 53 { 54 int u=read()+1,v=read()+1,val=read(); 55 ins(u,v,val); ins(v,u,val); 56 ans+=2*val; 57 } 58 //cout<<" "<<ans<<endl; 59 memset(bo,1,sizeof(bo)); 60 for (int i=1; i<=k; i++) 61 { 62 sum=0; mx=0; 63 for (int j=1; j<=n; j++) s1[j]=s2[j]=0; 64 dfs(1,0); 65 if (sum-c>0) 66 { 67 //cout<<" "<<sum<<" "<<c<<" "<<mx<<endl; 68 ans-=sum-c; 69 for (int p=s1[mx]; p; p=s1[v[p]]) val[p]=-1*val[p]; 70 for (int p=s2[mx]; p; p=s1[v[p]]) val[p]=-1*val[p]; 71 } 72 //cout<<" ans "<<" "<<ans<<endl; 73 } 74 printf("%d\n",ans); 75 } 76 } 77 /* 78 6 6 4 79 0 1 9 80 1 2 10 81 2 3 2 82 4 1 9 83 5 2 8 84 */
我太蒟蒻了,所以神犇们留下意见让我跪膜