BZOJ1912[Apio2010]patrol 巡逻

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1912

题解:嗯,这是一道很好的题。

转自:http://www.cnblogs.com/iwtwiioi/p/4126284.html

  对于 k==0 的情况: 
  我们发现遍历一棵树最后回到原点,那么对于所有的边,我们都是走过去,再走回来。 
  答案 (n1<<1)

  对于 k==1 的情况 
  设每条边长度为1,然后树上找最长链,然后这条链走过去就不再一步步往回了,直接从链底连一条边去链顶,然后链中间连的那些点,直接走过去再走回来,它们那些边的答案是不变的。 
  答案 (n1<<1)()+1 
  可以证明不能减得更多啦。

  z对于 k==2 的情况 
  设上一次的直径上的边的边长都为-1,因为再走一次会坑,然后树上找最长链。 
  答案 (n1<<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 }
View Code

注:可以想想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 */
View Code

 

posted @ 2016-06-17 21:21  ACist  阅读(203)  评论(0编辑  收藏  举报