图片加载可能有点慢,请跳过题面先看题解,谢谢
这道题目把模型简化后其实很简单,简化后的模型为:
有许多个小集合 \(P0,P2...Pn-1\) (即每个节点和与它相邻节点的并为 \(P\) ),现在要求出一种分组方式,使得每一组的元素的并为全集并且组数最多 $ $ 我们注意到,\(n\) 很小,完全可以将 \(P\) 压成一个二进制数,那么这就是一个比较简单的子集 \(dp\) 了。 设 \(vis[i]\) 为,在 \(i\) 状态下的覆盖情况(\(i\) 是一个二进制数,表示 \(P\) 的选取状态); 设 \(f[i]\) 为, 在 \(i\) 状态下能破坏的最大服务数(\(i\) 同上),则答案为 \(f[(1<<n)-1]\); $ $ 那么转移就很好写了:$f[i]=max(f[i],f[i $ ^ j]+1)\(,其中,\)\(j\) 为 \(i\) 的子集且 \(vis[j]=(1<<n)-1\) 另附枚举 \(i\) 的子集 \(j\) 的方式:for(j=i;j;j=(j-1)&i)//made by Hero_of_Someone#include#include #include #define il inline#define RG registerusing namespace std;il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar(); if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }int t,n,p[54],vis[1<<20],f[1<<20];il void init(){ for(int i=0;i