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 }

                              

  • 相关阅读:
    SqQueue(环状队列(顺序表结构))
    LinkQueue(链队列)
    CharMatch(括号匹配)
    LinkStack
    x-boot
    安装npm及cnpm(Windows)
    sourcetree跳过注册的方法
    Mysql 5.7 CentOS 7 安装MHA
    ORA-12519 ORA-12516
    lisp : set 与setq 函数
  • 原文地址:https://www.cnblogs.com/qywhy/p/10633376.html
Copyright © 2011-2022 走看看