zoukankan      html  css  js  c++  java
  • Gym

    题面

    题意:给你n(20)个点,m(40条边),让你给每条边染一种颜色,白色0元,红色2元,蓝色1元,现在要保证每一条白边相邻的有一条红边,问至少花多少

    题解:刚开始想的时候,好像觉得只用染红色和白色就够了?乱搞一通就发现不对了

            例如:5个点,5条边:1 2,   2 3  ,  3 4 , 4 5 , 5 2 .  如果只用红白,则答案为2条红边,2*2=4  但实际上,如果2 5染红,3 4染蓝,答案为3

            所以我们重新思考:什么时候染蓝色?

            我们假设一条边,如果染了红色,则他的2个端点,就标记为红色,如果我们枚举每个点是否红色(2^20),然后再看这个图

            我们发现,此时如果存在一条边的两个端点都没被染红,那么把这条边染蓝更优.

            所以我们利用状压,枚举每个点染红的状态(注意这个状态其实也是由边统计来的)

            dp[i]表示i集合为红的最小花费    dp[i+t]=dp[i]+2;  t=i | (1<<u) | (1<<v)  (其实u,v都要减一,不过在读入的时候处理掉了)

            然后再枚举每个状态,看蓝色的花费,统计出最小的答案

           

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,m,a[45],b[45],f[1024*1024+10];
     4 int main()
     5 {
     6     scanf("%d%d",&n,&m);
     7     for (int i=1;i<=m;i++) scanf("%d%d",&a[i],&b[i]),a[i]--,b[i]--;
     8     int nn=1<<n;
     9     for (int i=0;i<nn;i++) f[i]=(int)1e8;
    10     f[0]=0;
    11     for (int i=0;i<nn;i++)
    12     {
    13         if (f[i]!=(int)(1e8))
    14         {
    15             for (int j=1;j<=m;j++)
    16             {
    17                 int t=i|(1<<a[j])|(1<<b[j]);
    18                 f[t]=min(f[t],f[i]+2);
    19             }
    20         }
    21     }
    22     int ans=(int)(1e8);
    23     for (int i=0;i<nn;i++)
    24     {
    25         int qq=f[i];
    26         for (int j=1;j<=m;j++)
    27         {
    28             if ((i>>a[j])%2==0 && (i>>b[j])%2==0) qq++; 
    29         }
    30         ans=min(ans,qq);
    31     }
    32     cout<<ans<<endl;    
    33 }

                              

  • 相关阅读:
    类库探源——开头
    码的生产——(二维码、条形码)
    java 接口
    Eclipse下修改工程名
    Oracle 查询库中所有表名、字段名、字段名说明,查询表的数据条数、表名、中文表名、
    oracle中SQL根据生日日期查询年龄的方法
    TRUNCATE 删除表,无法回退。默认选择为整个表的内容,所以不能加条件。
    【kettle】window安装与配置
    SQL SELECT语句
    Oracle 查询类似 select top 的用法
  • 原文地址:https://www.cnblogs.com/qywhy/p/10633376.html
Copyright © 2011-2022 走看看