首页 > 其他分享 >[ABC310D] Peaceful Teams 题解

[ABC310D] Peaceful Teams 题解

时间:2023-07-18 13:11:11浏览次数:43  
标签:include return int 题解 Teams Peaceful ABC310D

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(T^n)\),无法通过,于是加一点点剪枝:

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

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

然后就飞过去了。

代码

#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;
}

标签:include,return,int,题解,Teams,Peaceful,ABC310D
From: https://www.cnblogs.com/TKXZ133/p/17562634.html

相关文章

  • NOI春季测试前模拟赛题解
    T312819命题工作直接容斥。总方案-一题出现四次-一题出现三次-一题出现两次。一题出现两次的情况略有不同,注意考虑周全。复杂度\(O(n)\)。codeT312891图上棋局有技巧的博弈论。如果当前点的所有出边均为先手必胜,那么当前点为先手必败。否则先手必胜。于是......
  • 题解 P2137 Gty的妹子树
    神奇的分块。假如没有\(2\)操作,我们可以直接用主席树解决。我们考虑将询问分块,每遍历完一块就将这一块内出现的所有修改更新。如果在块内,就把当前块之前的所有修改暴力算,当然只有修改的节点在询问的节点的子树内才会发生。具体的来说,我们可以用分块维护dfs序,并将块内的元素......
  • 题解 P4183 [USACO18JAN] Cow at Large P
    带有小trick的点分治。建议先做完弱化版再看。假如奶牛在\(u\),那么所需的最少农夫数为\(\sum\limits_{v\inson(u)}[dis(u,v)\geg_v][dis(u,fa_v)<g_{fa_v}]\)。其中\(dis(u,v)\)为\(u,v\)在树上的距离,\(g_u\)为\(u\)到离它最近的出入口的距离(BFS预处理),\(fa_u\)......
  • 题解 P9415 下楼
    不难推理出当初始绳长为\(len\),需要下降的距离为\(d\),并且满足\(d\lelen<2d\)时,最优的环套法可以只损失\(2d-len\)长度的绳子,留下\(2(len-d)\)的绳子。当\(2d\lelen\)时存在一种不损耗绳长的方法可以下到下一根钢管,即把整根绳子系成一个环,到达下面再剪断。正文:线......
  • 题解 P9437『XYGOI round1』一棵树
    换根DP。本蒟蒻最初没想到换根,把自己写自闭了...定义\(f_u\)为子树\(u\)中的每个结点走到\(u\)的贡献和,\(l_u\)为大于\(a_u\)的最小的\(10\)的幂次方数,\(sum_u\)为\(\sum\limits_{v\inson(u)}{f_v}\)。转移方程为:\(f_u=l_u\cdot\sum\limits_{v\inson(u)}{f_v}+......
  • 决策单调性优化DP 学习笔记 & P4767 [IOI2000] 邮局 题解
    0.题面题目描述高速公路旁边有一些村庄。高速公路表示为整数轴,每个村庄的位置用单个整数坐标标识。没有两个在同样地方的村庄。两个位置之间的距离是其整数坐标差的绝对值。邮局将建在一些,但不一定是所有的村庄中。为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局......
  • 题解 P7215
    点分治。考虑当前的分治重心的城市被完全联通。这可以用队列接解决。每次放入一种城市,就把那些城镇的父亲加入队列,如果存在城镇不在当前分治重心的联通块内,那么说明必定存在另一个分治重心能算到它,直接退出即可。剩下的和模板没有任何区别。复杂度\(O(n\logn)\)。code:#in......
  • 题解 P6329
    点分树模板题。是个神奇的算法。点分树就是将分治重心按照层级连边,每个节点父亲的联通块都包含了当前节点的联通块,且高度为\(\logn\)。可以解决不考虑树的形态的多次询问带修改的问题。对于这道题,我们可以在点分树的每个节点上记录两棵树状数组,分别与当前节点距离为\(k\)的......
  • 题解 P3345
    点分树。本题的核心问题在于不好直接确定补给站的位置。但是仔细思考后我们发现,对于当前节点,如果存在一个儿子的答案比它优,那么补给站一定在那个儿子的子树中。增量为\(w\times(sum_u-2\cdotsum_v)\)。当\(v\)优于\(u\)时,\(2\cdotsum_v>sum_u\)。如果\(v_2\)也满足,则......
  • 题解 P5384
    这题有紫??对于询问节点\(u\),倍增地跳到它的\(k\)级祖先,求其子树内有多少深度为\(dep_u\)的节点。我们考虑把询问离线,再通过dfs序把树拍平,然后扫一遍直接求就行了。复杂度\(O(n\logn)\)。code:#include<bits/stdc++.h>usingnamespacestd;constintN=1e6+5;inlin......