• CF1105E Helping Hiasat


    最大独立集

    神仙题,感觉不止2200的难度

    先要建图

    可以发现无论有多少个连续的1操作,都是可以看做1次1操作

    那么可以将以这1作为分组的界限,将连续的2操作分为一组

    然后将每一个朋友姓名的字符串用map哈希成数字

    此时将每一个朋友在哪一组出现过都处理出来

    称两个朋友是冲突的,当且仅当这两个朋友同时出现在任意一组中

    那么将这两个朋友之间连边,那么图就建出来了

    比赛时我就想到这里,然后用拓扑序乱搞,竟然水过了前29个点

    后来jzy大佬,喊了一声最大独立集,我就恍然大悟

    然后答案就是这张图的最大独立集

    最大独立集就是原图补图的最大团

    因为m是40的范围,直接暴力会超时,所以要有dp优化

    MYY大佬是折半搜索的(好吧我不想写

    当然,如果会高级算法也能直接过(然而我不会

    #include <bits/stdc++.h>
    #pragma GCC optimize(2)
    #define ll long long
    using namespace std;
    const int MAXN=100000+10;
    int n,m,w,si[51],vi[51],ans,g;
    int MIN,fx[51][51],dp[51],s[51];
    map <string,int> mp;
    struct node
    {
        int op;
        string name;
    }sh[MAXN];
    vector <int> f[MAXN],ti[51],e[51];
    set <pair<int,int> > q;
    bool check(int x,int y)
    {
        for (int i=0;i<(int)ti[x].size();i++)
        {
            vector <int> :: iterator it;
            it=lower_bound(ti[y].begin(),ti[y].end(),ti[x][i]);
            if (it==ti[y].end())
              continue;
            if (*it==ti[x][i])
              return true;
        }
        return false;
    }
    bool judge(int x,int end)
    {
        for (int i=1;i<end;i++)
        {
            if (!fx[s[i]][x])
              return false;
        }
        return true;
    }
    void dfs(int x,int wh)//暴力求出补图的最大团
    {
        if (x+m-wh+1<=ans || x+dp[wh]<=ans)
          return;
        for (int i=wh;i<=m;i++)
        {
            if (judge(i,x+1))
            {
                s[x+1]=i;
                dfs(x+1,i+1);
            }
        }
        if (x>ans)
          ans=x;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&sh[i].op);
            if (sh[i].op==2)
            {
                cin>>sh[i].name;
                if (mp[sh[i].name]==0)
                {
                    w++;
                    mp[sh[i].name]=w;//离散化
                }
            }
        }
        int bl=-1;
        w=0;
        for (int i=1;i<=n;i++)//分组
        {
            if (bl==-1 && sh[i].op==2)
            {
                w++;
                bl=0;
                f[w].push_back(mp[sh[i].name]);
            }
            else
            if (bl==0 && sh[i].op==2)
            {
                f[w].push_back(mp[sh[i].name]);
            }
            else
            if (bl==0 && sh[i].op==1)
              bl=-1;
        }
        for (int i=1;i<=w;i++)
        {
            for (int j=0;j<(int)f[i].size();j++)
              ti[f[i][j]].push_back(i);
        }
        for (int i=1;i<=m;i++)
        {
            for (int j=i+1;j<=m;j++)
            {
                if (check(i,j))
                {
                    e[i].push_back(j);
                    e[j].push_back(i);
                }
            }
        }
        for (int i=1;i<=m;i++)
        {
            for (int j=1;j<=m;j++)
              fx[i][j]=1;
        }
        for (int i=1;i<=m;i++)
        {
            for (int j=0;j<(int)e[i].size();j++)
              fx[i][e[i][j]]=0;//建出原图的补图
            fx[i][i]=0;
        }
        dp[m]=1;
        ans=0;
        for (int i=m-1;i>=1;i--)//求出补图的最大团
        {
            s[1]=i;
            dfs(1,i+1);
            dp[i]=ans;
        }
        printf("%d
    ",dp[1]);
    }
  • 相关阅读:
    Triggering effects when a container is resized
    Flex2:无边框透明背景MenuBar实现
    Using the isBranch() method to determine if a Tree item is a branch or leaf
    Flex3 Style 编辑工具
    Displaying a Tree control as a pop up for a Flex PopUpButton control
    Using a CheckBox control as a list item renderer in Flex
    Creating a ControlBar container in Flex using ActionScript
    .NET下的多线程编程4利用thread.Start()传递参数
    委托使用的实例
    算法大全—1冒泡排序法
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11258414.html
Copyright © 2020-2023  润新知