UVA-11795 (状压dp)

题意:

按照一定的顺序消灭n个机器人,每消灭一个机器人就可得到它的武器,每个机器人只有用特定的武器才能消灭,现在给定一个初始的武器,它能消灭一些机器人,每个机器人的武器能消灭那些机器人也给你了,现在要你求消灭n个机器人的顺序总数;

思路:

dp[i][k]表示在第i次操作时的用k表示已经挂掉的机器人的操作顺序数;

枚举第i次要攻击的机器人j;dp[i][x]+=dp[i-1][k];x是挂到j后k与j表示的状态;

AC代码:

/************************************************
┆  ┏┓   ┏┓ ┆
┆┏┛┻━━━┛┻┓ ┆
┆┃       ┃ ┆
┆┃   ━   ┃ ┆
┆┃ ┳┛ ┗┳ ┃ ┆
┆┃       ┃ ┆
┆┃   ┻   ┃ ┆
┆┗━┓    ┏━┛ ┆
┆  ┃    ┃  ┆      
┆  ┃    ┗━━━┓ ┆
┆  ┃  AC代马   ┣┓┆
┆  ┃           ┏┛┆
┆  ┗┓┓┏━┳┓┏┛ ┆
┆   ┃┫┫ ┃┫┫ ┆
┆   ┗┻┛ ┗┻┛ ┆
************************************************ */  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>

using namespace std;

#define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss));

typedef  long long LL;

template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<‘0‘||CH>‘9‘;F= CH==‘-‘,CH=getchar());
    for(num=0;CH>=‘0‘&&CH<=‘9‘;num=num*10+CH-‘0‘,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + ‘0‘);
    putchar(‘\n‘);
}

const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=1e9;
const int N=(1<<18);
const int maxn=(1<<8);
const double eps=1e-8;

char s[20][20];
int num[20],sword[N],n;
LL dp[18][N];
inline int getnum(int x)
{
   // int len=strlen(s[x]);
    int ans=0;
    For(i,0,n-1)
    {
        if(s[x][i]==‘1‘)ans+=(1<<i);
    }
    return ans;
}
int main()
{
        int t,Case=0;
        read(t);
        while(t--)
        {
            read(n);
            scanf("%s",s[0]);
            sword[0]=getnum(0);
            mst(dp,0);
            For(i,1,n)
            {
                scanf("%s",s[i]);
                num[i]=getnum(i);
            }
            For(i,1,(1<<n)-1)//预处理出每个状态下得到的武器情况
            {
                sword[i]=sword[0];
                for(int j=0;j<n;j++)
                {
                    if(i&(1<<j))sword[i]=(sword[i]|num[j+1]);
                }
            }
            dp[0][0]=1;
            For(i,1,n)
            {
                For(j,1,n)
                {
                    for(int k=0;k<(1<<n);k++)
                    {
                        if(k&(1<<(j-1)))continue;//如果第j个机器人已经挂掉就略过;
                        if(sword[k]&(1<<(j-1)))dp[i][k|(1<<(j-1))]+=dp[i-1][k];//如果有干掉第j个机器人的武器
                    }
                }
            }
            LL ans=dp[n][(1<<n)-1];
            printf("Case %d: %lld\n",++Case,ans);
        }
        return 0;
}

  

  

时间: 2024-08-03 03:06:33

UVA-11795 (状压dp)的相关文章

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的计算用到位运算,还

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

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

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 - 11825 状压DP

该题目是EMAXX推荐的练习题,刘汝佳的书也有解说 如果S0属于全集,那S0就可以作为一个分组,那么S分组数可以是best{当前S中S0的补集+1} 对于集合类的题目我觉得有点抽象,希望多做多理解把 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<

UVa 12235 状压DP Help Bubu

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

状压DP UVA 11795 Mega Man&#39;s Mission

题目传送门 1 /* 2 题意:洛克人有武器可以消灭机器人,还可以从被摧毁的机器人手里得到武器,问消灭全部机器人的顺序总数 3 状态压缩DP:看到数据只有16,就应该想到状压(并没有).因为是照解题报告写的,代码里加点注释,省的以后忘记了 4 */ 5 /************************************************ 6 * Author :Running_Time 7 * Created Time :2015-8-8 10:41:28 8 * File Nam

uva 11795 Mega Man&#39;s Mission 状压dp

// uva 11795 Mega Man's Mission 状压dp // 设r[i]表示第i个机器人所拥有的武器的数目 // r[0]表示初始时洛克人所拥有的武器数 // w[s]表示杀死集合s中的机器人后所得的武器数 // d[s]表示能杀死集合s中的机器人的顺序总数 // d[s] = sigma(d[s-{i}]) 其中i是集合s中的机器人 // 还有一点就是w[S-{i}]的武器可以杀死i. // 注意: // 1)初始的时候d[0]=1,其他均为0.这个很好理解,因为杀死 //

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in