Loading

[ABC310D] Peaceful Teams 题解

Peaceful Teams

题目大意#

n 个人分成 T 组,要求每组不能包含敌对的人,问有多少种分法。

思路分析#

注意到 n,T 均很小,考虑爆搜。

注意到直接枚举会枚举到分组顺序的全排列,所以可以强行嵌定大小关系去重。

void dfs(int s){
    if(s==n+1){
        for(int i=1;i<=t;i++) if(!tt[i]) return ;
        for(int i=2;i<=t;i++) if(sk[i-1][1]>sk[i][1]) return ;//去重
        ans++;
        return ;
    }
    for(int i=1;i<=t;i++){
        int flag=0;
        for(int j=1;j<=tt[i];j++) if(bad[sk[i][j]][s]){flag=1;break;}//判断敌对
        if(flag) continue;
        sk[i][++tt[i]]=s;
        dfs(s+1);
        tt[i]--; 
    }
}

正常搜索的时间复杂度为 O(Tn),无法通过,于是加一点点剪枝:

  • 如果当前人数小于当前的空组数,那么填到最后一定存在空组,直接返回。

  • 每次搜索都优先判定是否合法。

然后就飞过去了。

代码#

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>
 
using namespace std;
const int N=110;
 
int ans,n,t,m,in1,in2;
int bad[N][N],sk[N][N],tt[N];
 
void dfs(int s){
    for(int i=2;i<=t;i++) 
        if(tt[i-1]&&tt[i]&&sk[i-1][1]>sk[i][1]) return ; 
    int cnt=0;
    for(int i=1;i<=t;i++) 
        if(!tt[i]) cnt++;
    if(n-s+1<cnt) return ;
    if(s==n+1){
        for(int i=1;i<=t;i++) if(!tt[i]) return ;
        ans++;
        return ;
    }
    for(int i=1;i<=t;i++){
        int flag=0;
        for(int j=1;j<=tt[i];j++) if(bad[sk[i][j]][s]){flag=1;break;}
        if(flag) continue;
        sk[i][++tt[i]]=s;
        dfs(s+1);
        tt[i]--; 
    }
}
 
int main(){
    scanf("%d%d%d",&n,&t,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&in1,&in2);
        bad[in1][in2]=bad[in2][in1]=1;
    }
    dfs(1);
    cout<<ans<<'\n';
    return 0;
}

作者:TKXZ133

出处:https://www.cnblogs.com/TKXZ133/p/17562634.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   TKXZ133  阅读(76)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示