HDU 4770 DFS&状压

一个n*m的房间有的房间是可破坏的,其他不可破坏,现在给你一些L型的灯,其中只有一个可以旋转,其他不能,让你用最少的灯覆盖所有的可破坏区域,且不能覆盖不可破坏的区域。

枚举旋转的灯,对剩下的DFS即可,状压存储已经被点亮的灯

#include "stdio.h"
#include "string.h"

struct P
{
    int x,y;
}p[21];

int ans,n,m,cnt,aim,b[21];
char str[210][210];

int judge(int x,int y)
{
    if (x>=0 && x<n && y>=0 && y<m && str[x][y]=='#') return 0;
    return 1;
}

void dfs(int k,int sum,int mark,int light)
{
    int i,j,ll;

    if (sum>=ans) return ;
    if (light==aim) {ans=sum; return ;}
    if (k>=cnt) return ;

    dfs(k+1,sum,mark,light);

    for (i=k;k<cnt;k++)
        if (i!=mark)
        {
            ll=light|b[i];
            if (judge(p[i].x-1,p[i].y)==0 || judge(p[i].x,p[i].y+1)==0) continue;
            for (j=0;j<cnt;j++)
            {
                if (p[i].x-1==p[j].x && p[i].y==p[j].y) ll|=b[j];
                if (p[i].x==p[j].x && p[i].y+1==p[j].y) ll|=b[j];
            }
            dfs(k+1,sum+1,mark,ll);
        }
}
int main()
{
    int i,j,mark,light;
    b[0]=1;
    for (i=1;i<=16;i++)
        b[i]=b[i-1]*2;

    while (scanf("%d%d",&n,&m)!=EOF)
    {
        if (n+m==0) break;
        for (i=0;i<n;i++)
            scanf("%s",str[i]);

        cnt=0;
        for (i=0;i<n;i++)
            for (j=0;j<m;j++)
            if (str[i][j]=='.')
            {
                p[cnt].x=i;
                p[cnt].y=j;
                cnt++;
            }
        if (cnt==0)
        {
            printf("0\n");
            continue;
        }
        ans=100000;
        aim=b[cnt]-1;

        dfs(0,0,-1,0);
        for (i=0;i<cnt;i++)
        {
            if (judge(p[i].x-1,p[i].y) && judge(p[i].x,p[i].y-1))
            {
                mark=i;
                light=b[i];
                for (j=0;j<cnt;j++)
                {
                    if (p[j].x==p[i].x && p[j].y==p[i].y-1) light|=b[j];
                    if (p[j].x==p[i].x-1 && p[j].y==p[i].y) light|=b[j];
                }
                dfs(0,1,mark,light);
            }

            if (judge(p[i].x,p[i].y-1) && judge(p[i].x+1,p[i].y))
            {
                mark=i;
                light=b[i];
                for (j=0;j<cnt;j++)
                {
                    if(p[j].x==p[i].x && p[j].y==p[i].y-1) light|=b[j];
                    if(p[j].x==p[i].x+1 && p[j].y==p[i].y) light|=b[j];
                }
                dfs(0,1,mark,light);
            }

            if (judge(p[i].x,p[i].y+1) && judge(p[i].x+1,p[i].y))
            {
                mark=i;
                light=b[i];
                for (j=0;j<cnt;j++)
                {
                    if (p[j].x==p[i].x && p[j].y==p[i].y+1) light|=b[j];
                    if (p[j].x==p[i].x+1 && p[j].y==p[i].y) light|=b[j];
                }
                dfs(0,1,mark,light);
            }
        }
        if (ans==100000) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-11-05 12:34:35

HDU 4770 DFS&状压的相关文章

HDU 4284Travel(状压DP)

HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1 由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然

HDU Untitled(状压DP OR dfs枚举子集)

Untitled Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 325    Accepted Submission(s): 169 Problem Description There is an integer a and n integers b1,-,bn. After selecting some numbers from b

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

hdu 2209 bfs+状压

http://acm.hdu.edu.cn/showproblem.php?pid=2209 不知为啥有种直觉,会出状压+搜索的题,刷几道先 简单的BFS,状压表示牌的状态, //#pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <cstring> #include <algorithm> #include <string> #

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6

HDU 4771 BFS + 状压

Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1343    Accepted Submission(s): 642 Problem Description Harry Potter has some precious. For example, his invisib

hdu 2825 (Aho-Corasick &amp; 状压DP) - xgtao -

题目链接 给出m(m<=10)个模板串,问长度为n(n<=25)的字符串包含至少k个模板串的种类数,对20090717取模. 套路,有多个模板串考虑Aho-Corasick,因为想了很久找不到什么可行办法做,就考虑Dp,因为m<=10,所以可以有状压来检查当前状态下已经包含多少个模板串了,因为在一棵trie树上,那么定义状态也好定义,dp[len][id][s]表示长度为len时处在第id个节点并且状态为s,转移方程为dp[len+1][nextid][s|nexts] += dp[le

HDU 3619 优先队列+状压+bfs

Heroes of Might and Magic Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 170    Accepted Submission(s): 74 Problem Description After a very long journey and uncountable number of uphill battles

HDU 5045 DP+状压

2014 ACM/ICPC Asia Regional Shanghai Online 给出N个人做M道题的正确率,每道题只能由一个人做出,并且当所有人都做出来且仅做出一道题时,做过题的人才可以继续做题,求最大期望. 一共只有10个人,状压存储每个人是否已经做出题目,如果都作出则状态清0: #include "stdio.h" #include "string.h" double Max(double a,double b) { if (a<b) return