G - Party CodeForces - 906C -状态压缩+DFS

本文介绍了解决CodeForces-906C问题的方法,该问题要求找到最少的操作数使关系群内所有人相互认识。通过使用状态压缩技巧,将人际关系用二进制表示,并利用DFS进行搜索,最终找到最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • G - Party

  •  CodeForces - 906C 
  • 题意:给出一些关系都是双人关系而且无向,可以进行一步操作,每一步操作是选择一个人,
  • 让这个人认识关系群里面的人都相互认识,求一个最小操作数
  • 思路:第二次碰到这样的状态压缩题目了,把一个人所认识其他人用二进制来表示1<<n-1为则表示这个人认识n个人
  • 因为1<<n-1 二进制有n为全为1,就是说二进制的位置代表第几个朋友,0表示不认识,1表示 认识
  • 则最初初始化为 认识自己 即每一个人的最初二进制关系网为 1<<i,这里注意因为二进制中1左移0位为1,
  • 所以所有人的编号要减一即还是n个人把原来的1-n变为了0-n-1 这样 正好与二进制相适应
  • 最核心的就是 DFS过程了,代码中注释的小细节不再解释,总题思路就是,刚开始copy了n个最初的关系网
  • 最后通过第n层的关系网络检测这种操作是否是有效(所有人的关系网都为(1<<n)-1)操作,
  • (并且有一个如果比已知答案更差的就return的剪枝过程)
  • 由于是先递归到底在往前回溯所以不会对最前面的关系网产生破坏,而后面的关系网改变后还可以通过
  • 每一次都有一个 memcpy(dp[x+1],dp[x],sizeof(dp[x]));进行更新每一种选择
  • 每次x<n的dfs进入后有两种选择一直不选择这个人直接往下dfs(x+1),另一种是选择这个人,把这个人认识的人
  • 全部更新到下一层。然后这样搜索最优解即可,
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 25
    int dp[maxn][maxn];
    stack<int>ans,qyn;
    int n,m,u,v;
    void dfs(int x)
    {
        if(qyn.size()>=ans.size())return ;//更差的情况进行剪枝
        if(x==n)
        {
            for(int i=0; i<n; i++)
                if(dp[x][i]!=(1<<n)-1)return ;
            //判断是否是一种成功让所有人都认识的情况
            ans=qyn;
            return ;
        }
        memcpy(dp[x+1],dp[x],sizeof(dp[x]));
        dfs(x+1);
        for(int i=0; i<n; i++)
            if(dp[x][x]&(1<<i))dp[x+1][i]|=dp[x][x];
        qyn.push(x+1);
        dfs(x+1);
        qyn.pop();
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
        {
            ans.push(i+1);
            dp[0][i]=1<<i;
        }
        while(m--)
        {
            scanf("%d%d",&u,&v);
            u--;
            v--;
            dp[0][u]|=1<<v;
            dp[0][v]|=1<<u;
        }
        dfs(0);
        printf("%d\n",ans.size());
        while(!ans.empty())
        {
            if(ans.size()==1)
                printf("%d\n",ans.top());
            else
                printf("%d ",ans.top());
            ans.pop();
        }
        return 0;
    }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值