zoukankan      html  css  js  c++  java
  • [Codeforces Round #508 (Div. 2)][Codeforces 1038E. Maximum Matching]

    前几天给舍友讲这题的时候感觉挺有意思的,就贴上来吧...

    题目链接:1038E - Maximum Matching

    题目大意:有(n)个棒子,每个条两端有颜色(c1,c2)以及他的价值(v),要求选取若干个棒子拼接起来(要求连接处的颜色相同,棒子可以反转),求最大价值总和。

    题解:设(c1==c2)的为同色棒子,反之为异色

       可以发现偶数个异色棒子可以拼为一个长长的同色棒子,奇数个则可以拼为一个长长的异色棒子,因此可以预处理(F[i][j])表示若将所有((i,j))当做异色棒子来用所能得到的价值,(G[i][j])表示当做同色棒子来用所能得到的价值。显然他们的值为所有颜色为((i,j))的价值总和(-kcdot)颜色为((i,j))的最小价值,k等于0或1,由当前颜色的数目决定。

       对于同色的棒子,可以发现,若当前已经拼好的棒子里颜色(c)出现过,则可以将所有颜色为(c)的同色棒子塞进去以增加答案。

       接下去就是直接暴力DFS了,枚举起点的颜色,然后暴力考虑可以接哪些颜色,每次进入下一层的时候更新一次答案。更新答案就按照上面所说的那样,判断哪些颜色出现过,并将所有包含此颜色的异色棒子当做同色棒子来用塞进去。这里要注意一点,虽然塞进去的时候是当做同色来塞,但这种操作可能会导致新出现了一种颜色,而新颜色的出现可能还会导致答案的增加(即有包含新颜色的棒子)。因此这样子的操作还要再进行若干次,3次是肯定够的。最后再把所有已出现颜色的同色棒子加入就好了。

       由于颜色组合只有10种((1,2)和(2,1)算一种),因此DFS的复杂度不会超过(O(4^{10})),再乘上update的复杂度则为(O(4^{13})),水过去是没有压力的

    代码中将颜色对((c1,c2))进行了标号处理

    #include<bits/stdc++.h>
    using namespace std;
    #define N 101
    int n,s[N],cnt[N],m[N],F[N],G[N],c1,c2,v,ans;
    bool x[5][5],f[5];
    void update()
    {
        bool g[5],X[5][5];
        for(int i=1;i<=4;i++)g[i]=f[i];
        for(int i=1;i<=4;i++)
          for(int j=i+1;j<=4;j++)
            X[i][j]=x[i][j];
        int res=0;
        for(int i=1;i<=4;i++)
          for(int j=i+1;j<=4;j++)
            if(x[i][j])res+=F[i*5+j];
        for(int _=0;_<3;_++)
        for(int i=1;i<=4;i++)
          for(int j=i+1;j<=4;j++)
            if(!X[i][j] && (g[i]||g[j]) && cnt[i*5+j]>1)
              res+=G[i*5+j],X[i][j]=true,g[i]=true,g[j]=true;
        for(int i=1;i<=4;i++)if(g[i])res+=s[i];
        ans=max(ans,res);
    }
    int get(int i,int j){if(i>j)swap(i,j);return i*5+j;}
    void dfs(int i)
    {
        update();
        for(int j=1;j<=4;j++)
          if(!x[i][j] && cnt[get(i,j)])
            x[i][j]=x[j][i]=f[j]=true,dfs(j),x[i][j]=x[j][i]=f[j]=false;
    }
    int main()
    {
        memset(m,0x3f,sizeof(m));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          {
          scanf("%d%d%d",&c1,&v,&c2);
          if(c1==c2){s[c1]+=v;continue;}
          if(c1>c2)swap(c1,c2);
          int id=c1*5+c2;
          cnt[id]++,m[id]=min(m[id],v),s[id]+=v;
          }
        for(int i=1;i<=4;i++)
          for(int j=i+1;j<=4;j++)
            {
            int id=i*5+j;
            if(cnt[id])F[id]=cnt[id]&1?s[id]:(s[id]-m[id]);
            G[id]=cnt[id]&1?(s[id]-m[id]):s[id];
            }
        for(int i=1;i<=4;i++)
          f[i]=true,dfs(i),f[i]=false;
        return printf("%d
    ",ans),0;
    }
    View Code
  • 相关阅读:
    Codeforces 590 A:Median Smoothing
    HDU 1024:Max Sum Plus Plus 经典动态规划之最大M子段和
    POJ 1027:The Same Game 较(chao)为(ji)复(ma)杂(fan)的模拟
    【算法学习】 在一天的24小时之中,时钟的时针、分针和秒针完全重合在一起的时候有几次?
    【读书笔记】 spinlock, mutex and rwlock 的性能比较
    【读书笔记】 nginx 负载均衡测试
    【读书笔记】 多线程程序常见bug
    关注一下 hurd OS的开发
    【读书笔记】 分布式文件存储系统 MogileFS
    【读书笔记】 nginx + memcached 高速缓存
  • 原文地址:https://www.cnblogs.com/DeaphetS/p/9661317.html
Copyright © 2011-2022 走看看