UVA - 11825 状压DP

该题目是EMAXX推荐的练习题,刘汝佳的书也有解说

如果S0属于全集,那S0就可以作为一个分组,那么S分组数可以是best{当前S中S0的补集+1}

对于集合类的题目我觉得有点抽象,希望多做多理解把

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define iin(a) scanf("%d",&a)
#define lin(a) scanf("%lld",&a)
#define din(a) scanf("%lf",&a)
#define s0(a) scanf("%s",a)
#define s1(a) scanf("%s",a+1)
#define print(a) printf("%lld",(ll)a)
#define enter putchar(‘\n‘)
#define blank putchar(‘ ‘)
#define println(a) printf("%lld\n",(ll)a)
#define IOS ios::sync_with_stdio(0)
using namespace std;
const int maxn = 1e6+11;
const int oo = 0x3f3f3f3f;
const double eps = 1e-7;
typedef long long ll;
ll read(){
    ll x=0,f=1;register char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
int main(){
    int kase=0,n,m,x,P[666],U[1<<17|1],dp[1<<17|1];
    while(cin>>n){
        if(n==0)break;
        rep(i,0,n-1){
            m=read();
            P[i]=1<<i;
            rep(j,1,m){
                x=read();
                P[i]|=(1<<x);
            }
        }
        rep(S,0,(1<<n)-1){//并集枚举
            U[S]=0;
            rep(i,0,n-1){
                if((S>>i)&1) U[S]|=P[i];
            }
        }
        dp[0]=0; x=(1<<n)-1;//dp[S]:集合S最多可分成dp[S]组
        rep(S,1,(1<<n)-1){
            dp[S]=0;
            for(int S0=S;S0;S0=(S0-1)&S){
                if(U[S0]==x) dp[S]=max(dp[S],dp[S^S0]+1);
            }
        }
        printf("Case %d: %d\n",++kase,dp[(1<<n)-1]);
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/caturra/p/8456522.html

时间: 2024-10-01 00:38:05

UVA - 11825 状压DP的相关文章

UVa 11825 (状压DP) Hackers&#39; Crackdown

这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服务器相连.对于每台服务器,你可以选择停止该台以及与这台服务器相连的服务器的一项服务.如果一台服务器的所有服务都被停止,则这台服务器瘫痪.问最多能使多少台服务器瘫痪 转化为数学模型(题目是如何抽象成这种数学模型的也要好好想想): 把n个集合尽可能多的分成若干组,使得每组所有集合的并集为全集.这里集合P

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

Sharing Chocolate - UVa 1099 状压dp

Chocolate in its many forms is enjoyed by millions of people around the world every day. It is a truly universal candy available in virtually every country around the world. You find that the only thing better than eating chocolate is to share it wit

UVa 1252 (状压DP + 记忆化搜索) Twenty Questions

题意: 有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数. 每次只可以询问该数的第K为是否为1. 问采用最优询问策略,则最少需要询问多少次能保证猜到. 比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1. 分析: d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次. 如果下一次询问第k位,则询问次数为: 然后取所有k里的最小值即可. 预处理: 对于每个s和a

UVA - 1412 状压dp九进制表示状态

此题难点在于用九进制表示状态,并且转移 这里九进制用vector表示,再用map作为此状态特有的标记 此处用刷表法,每一种状态转移都经历一遍,最终状态就是正确答案,注意界限 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<stack> #include<queue> #include&

UVa 12235 状压DP Help Bubu

题解戳这 一开始没看懂题解,后来想明白以后,d(i, j, s, x)是考虑第i本书的时候,前面已经拿走了j本书,剩下的书的种类的二进制状态为s,剩下的最后一本书的编号为x,所能得到的最小混乱度. 这里状态定义的时候,先不考虑把拿出来的书放回去. 最后统计答案的时候,把那些拿出来的书再加上. all是所有n本书的状态,s是剩下书的种类的状态. 如果拿出来的书中有和前面高度相同的,直接插到相邻的位置就行了,不会增加混乱度. 如果拿出来的书中没有和前面高度相同的,不管放在那里混乱度都会加1,这样所增

uva 11825 Hackers&amp;#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中全部集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中全部集合的并集,dp[s]表示子集s最多能够分成多少组,则 假设co

UVA 11825 Hackers&#39; Crackdown 状压DP

感觉白书上的做法很神! 首先状压表示电脑之间的联通关系,然后预处理出所有关闭电脑的组合达到的状态,然后枚举每个状态并且枚举每个状态的所有子集,之后无脑递推就木有了. 关于枚举一个状态所有子集的小技巧:假设当前状态是S0 有 for s = s0; s != 0; s =  (s - 1) & s0 #include <cstdio> #include <cstring> #include <iostream> #include <map> #incl

uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有相同的n种服务),对每台计算机,你可以选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让更多的服务瘫痪(没有计算机有该项服务). 思路:(见大白70页,我的方程与大白不同) 把n个集合P1.P2.Pn分成尽量多的组,使得每组中所有集合的并集等于全集,这里的集合Pi是计算机i及其相邻计算机的集合,用cover[i]表示若干Pi的集合S中所有集合的并集,dp[s]表示子集s最多可以分成多少组,则 如果cove