[CodeForces-375E]Red and Black Tree

题目大意:
  给你一棵带边权的树,每个结点可能是红色或者黑色,你可以交换若干个点对使得任意一个红点到达与其最近的黑点的距离小于等于m。

思路:
  动态规划。
  f[i][j][k]表示以i为根的子树中,连向结点j,子树中已经确定有k个是黑点所需要的最小交换次数。
  best[i][k]表示以i为根的子树,已经确定有k个是黑点所需要的最小交换次数。
  设当前根为x,子结点为y,连向结点i,总共确定了k个黑点,新确定了l个黑点,转移方程为:
  f[x][i][k]=min(min{f[x][i][k-l]+best[y][l]},min{f[x][i][k-l+1]+f[y][i][l]-!col[i]});
  当然要判断新连向的点与当前根的距离,这可以事先跑一遍O(n^3)的Floyd。
  最后会被卡内存,据lyx介绍,由于n<=500,可以用uint16卡过去。

 1 #include<cstdio>
 2 #include<vector>
 3 typedef unsigned short uint16; 
 4 inline int getint() {
 5     register char ch;
 6     while(!__builtin_isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(__builtin_isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 template<typename _T1,typename _T2>
12 inline _T1 min(const _T1 &a,const _T2 &b) {
13     return a<b?a:b;
14 }
15 template<typename _T1,typename _T2>
16 inline _T1 max(const _T1 &a,const _T2 &b) {
17     return a>b?a:b;
18 }
19 const uint16 inf=~0;
20 const uint16 N=501;
21 bool col[N];
22 uint16 n,s;
23 int m;
24 int dis[N][N];
25 std::vector<uint16> e[N];
26 inline void add_edge(const uint16 &u,const uint16 &v,const int &w) {
27     e[u].push_back(v);
28     e[v].push_back(u);
29     dis[u][v]=dis[v][u]=w;
30 }
31 uint16 f[N][N][N],best[N][N],size[N];
32 void dfs(const uint16 &x,const uint16 &par) {
33     for(uint16 i=0;i<e[x].size();i++) {
34         const uint16 &y=e[x][i];
35         if(y==par) continue;
36         dfs(y,x);
37     }
38     for(register uint16 i=1;i<=n;i++) {
39         if(dis[x][i]>m) continue;
40         size[x]=1;
41         f[x][i][1]=!col[i];
42         for(register uint16 j=0;j<e[x].size();j++) {
43             const uint16 &y=e[x][j];
44             if(y==par) continue;
45             for(register uint16 k=min(s,size[x]+size[y]);;k--) {
46                 uint16 tmp=inf;
47                 for(register uint16 j=max(k-size[x],0);j<=min(k,size[y]);j++) {
48                     tmp=min(tmp,f[x][i][k-j]+best[y][j]);
49                 }
50                 for(register uint16 j=max(k-size[x],0)+1;j<=min(k,size[y]);j++) {
51                     tmp=min(tmp,f[x][i][k-j+1]+f[y][i][j]-!col[i]);
52                 }
53                 f[x][i][k]=tmp;
54                 if(!k) break;
55             }
56             size[x]+=size[y];
57         }
58     }
59     for(register uint16 i=1;i<=s;i++) {
60         best[x][i]=inf;
61         for(register uint16 j=1;j<=n;j++) {
62             best[x][i]=min(best[x][i],f[x][j][i]);
63         }
64     }
65 }
66 int main() {
67     n=getint(),m=getint();
68     for(register uint16 i=1;i<=n;i++) {
69         s+=(col[i]=getint());
70     }
71     __builtin_memset(dis,0x3f,sizeof dis);
72     for(register uint16 i=1;i<n;i++) {
73         const uint16 u=getint(),v=getint();
74         const int w=getint();
75         add_edge(u,v,w);
76     }
77     for(register uint16 k=1;k<=n;k++) {
78         for(register uint16 i=1;i<=n;i++) {
79             for(register uint16 j=1;j<=n;j++) {
80                 dis[i][j]=i==j?0:min(dis[i][j],dis[i][k]+dis[k][j]);
81             }
82         }
83     }
84     __builtin_memset(f,0xff,sizeof f);
85     __builtin_memset(best,0xff,sizeof best);
86     dfs(1,0);
87     __builtin_printf("%d\n",best[1][s]==inf?-1:best[1][s]);
88     return 0;
89 }

 

转载于:https://www.cnblogs.com/skylee03/p/7703565.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值