• 编译


    [Description]
    山山是 2017 级信奥班的成员,因为喜欢玩 Android 系统而出名。
    山山写出了一个伟大的 C++工程,一共包含 N 个源文件。在山山的脑海中,N 个源文
    件构成一个树形结构。每一个源文件是树上的一个节点,其中 1 号节点是树根。
    现在,山山开始编译这个工程。每次他会从树上选择一条链(包含两个端点)进行编译。
    由于编译器的特性,要求这条链的一个端点必须是另一个端点的祖先。一条链可以退化成一
    个点。每个源文件都需要被编译恰好一次。
    每一个源文件都有一个两位十六进制数的标志值(范围从 00 到 ff)。对于每一条选择的
    链,把该上面所有源文件的标志值异或起来,得到这条链的特征值。把所有选择的链的特征
    值相加,得到这次编译的代价。现在山山想知道至少选择几条链才能编译所有文件。在选择
    的链数目最小的时候,编译的代价最小是多少。
    [Input]
    第一行一个整数 N。
    以下一行,N 个两位十六进制数,表示第 1 号源文件到第 N 号源文件的特征值。
    (十六进制
    数中的字母采取小写,不足两位的在前面补零。亦即 C/C++中使用”%02x”输出的格式。
    )
    以下(N - 1)行,每行两个整数,给出树上的一条边所连接的两个顶点。
    [Output]
    一行两个整数。依次为,选择的链的最小数目、编译的最小代价。两个数均以十进制形式输
    出。
    [Sample]


    说明:最优方案为(1, 3), (2, 4), (5)或(1, 3), (2, 5), (4)。
    [Tips]
    0 ≤ N ≤ 20,000。

    因为要求链的一个端点必须是另一个端点的祖先,因此可以论证,链的数量等于
    叶子结点的数量;因此需要求的只有最小代价。
    定义 dp[u][s] 为考虑子树 u ,并且点 u 所属的链当前的异或和为 s 时的最小代价。
    由贪心法,每一个非叶子的点都必与一个子节点相连(否则链的数量无法达到最小),
    因此对每一个点枚举与它相连的子节点即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 typedef long long lol;
     7 struct Node
     8 {
     9   int next,to;
    10 }edge[40001];
    11 int num,head[20001];
    12 lol f[20001][256],t[20001],cnt,cost[20001],n;
    13 void add(int u,int v)
    14 {
    15   num++;
    16   edge[num].next=head[u];
    17   head[u]=num;
    18   edge[num].to=v;
    19 }
    20 void dfs(int x,int pa)
    21 {int flag=0,i,j;
    22   lol sum=0;
    23   for (i=head[x];i;i=edge[i].next)
    24     {
    25       int v=edge[i].to;
    26       if (v!=pa)
    27     {flag=1;
    28       dfs(v,x);
    29       sum+=t[v];
    30     }
    31     }
    32   if (flag==0) 
    33     {
    34       ++cnt;
    35       f[x][cost[x]]=cost[x];
    36     }
    37   for (i=head[x];i;i=edge[i].next)
    38     {
    39       int v=edge[i].to;
    40       if (v!=pa)
    41     {
    42       for (j=0;j<=255;j++)
    43         {
    44           f[x][j^cost[x]]=min(f[x][j^cost[x]],sum-t[v]+f[v][j]+(j^cost[x])-j);
    45         }
    46     }
    47     }
    48   for (i=0;i<=255;i++)
    49     t[x]=min(t[x],f[x][i]);
    50 }
    51 int main()
    52 {int i,u,v;
    53   cin>>n;
    54   memset(f,127/2,sizeof(f));
    55   memset(t,127/2,sizeof(t));
    56   char ch=getchar();
    57   for(i=1;i<=n;i++)
    58   {
    59     while(!(ch>='0'&&ch<='9'||ch>='a'&&ch<='f'))ch=getchar();
    60     while(ch>='0'&&ch<='9'||ch>='a'&&ch<='f')
    61     {
    62       cost[i]=cost[i]*16;
    63       if(ch<='9'&&ch>='0')cost[i]+=ch-'0';
    64       else cost[i]+=ch-'a'+10;
    65       ch=getchar();
    66     }
    67   }
    68   for (i=1;i<=n-1;i++)
    69     {
    70       scanf("%d%d",&u,&v);
    71       add(u,v);add(v,u);
    72     }
    73   dfs(1,0);
    74   cout<<cnt<<' '<<t[1];
    75 }
  • 相关阅读:
    整数拆分
    win8 使用notepad++写C代码
    hessian客户端调用服务端测试类
    多线程环境下保证实现单线程的案例
    windows server 2008开机启动多个tomcat服务方法及遇到问题
    解决加载静态文件无法被浏览器缓存问题
    【拦截器】HandlerInterceptor接口
    【pac4j】OAuth 认证机制 入门篇
    【Linux部署 · JDK】在linux系统安装jdk
    【Linux部署 · GIT】在linux系统安装git和配置实现SSH
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7699669.html
Copyright © 2020-2023  润新知