• HDU 5838 (状压DP+容斥)


    Problem Mountain

    题目大意

      给定一张n*m的地图,由 . 和 X 组成。要求给每个点一个1~n*m的数字(每个点不同),使得编号为X的点小于其周围的点,编号为.的点至少大于一个其周围的点。

        n<=5 , m<=5。

    解题分析

      考虑从1~n*m,从小到大依次填数,则如果某个位置编号为X且该位置还未填数,那么其周围的点均不能填数。

      令dp[i][j]表示填到第i个数,状态为j 。 令X的个数为cnt,那么 j ∈[ 0 , 1<<cnt)。

      一种情况为第i个数填在 X 的位置上,那么dp[i][j] 可以由 dp[i-1][j-{x}] 转移过来。 j - {x} 表示去掉某个X后的状态。

      另一种情况为第i个数填在 . 的位置,那么首先预处理一下w[j]表示状态为j时有多少个位置是可以填的,那么dp[i]][j] += dp[i-1][j] * (w[j] - (i-1))

      又因为要保证遍号为.的点至少大于一个其周围的点,dfs容斥一下。

    参考程序

      1 #include <map>
      2 #include <set>
      3 #include <stack>
      4 #include <queue>
      5 #include <cmath>
      6 #include <ctime>
      7 #include <string>
      8 #include <vector>
      9 #include <cstdio>
     10 #include <cstdlib>
     11 #include <cstring>
     12 #include <cassert>
     13 #include <iostream>
     14 #include <algorithm>
     15 #pragma comment(linker,"/STACK:102400000,102400000")
     16 using namespace std;
     17 
     18 #define N 100008             
     19 #define M 50008    
     20 #define LL long long
     21 #define lson l,m,rt<<1
     22 #define rson m+1,r,rt<<1|1 
     23 #define clr(x,v) memset(x,v,sizeof(x));
     24 #define rep(x,y,z) for (int x=y;x<=z;x++)
     25 #define repd(x,y,z) for (int x=y;x>=z;x--)
     26 const int mo  = 772002;
     27 const int inf = 0x3f3f3f3f;
     28 const int INF = 2000000000;
     29 /**************************************************************************/
     30 int n,m,ans,dp[30][1024],w[1024],tx[10],ty[10];
     31 char mp[10][10];
     32 int flag[10][10];
     33 const int dx[9]={-1,-1,-1,0,0,0,1,1,1};
     34 const int dy[9]={-1,0,1,-1,0,1,-1,0,1};
     35 void up(int &x,int y){
     36     x = (x + y) % mo;
     37     if (x>=mo) x-=mo;
     38 }
     39 int solve(){
     40     int cnt=0;
     41     rep(i,1,n) rep(j,1,m)
     42         if (mp[i][j]=='X'){
     43             tx[++cnt]=i;
     44             ty[cnt]=j;
     45         }
     46     for (int i=0;i<1<<cnt;i++){
     47         clr(flag,0);
     48         for (int j=1;j<=cnt;j++)
     49             if (i & 1<<j-1)
     50                 for (int k=0;k<9;k++) flag[tx[j]+dx[k]][ty[j]+dy[k]]=1;
     51         w[i]=0;
     52         rep(j,1,n) rep(k,1,m)
     53                 if (!flag[j][k]) w[i]++;
     54     }
     55     clr(dp,0);
     56     dp[0][0]=1;
     57     for (int i=1;i<=n*m;i++)
     58         for (int j=0;j<1<<cnt;j++)
     59         {
     60             for (int k=1;k<=cnt;k++)
     61                 if (j & 1<<k-1) 
     62                     up(dp[i][j],dp[i-1][j - (1<<k-1)]);
     63             up(dp[i][j],dp[i-1][j]*(w[j]-i+1));
     64         }
     65     return dp[n*m][(1<<cnt)-1];
     66 }
     67 void dfs(int x,int y,int p){
     68     if (y==m+1){
     69         x++;
     70         y=1; 
     71     }
     72     if (x==n+1){ 
     73         ans=(ans + solve()*p) % mo;
     74         if (ans<0) ans+=mo;
     75         return;
     76     }
     77     int flag=0;
     78     for (int i=0;i<9;i++) if (i!=4&&mp[x+dx[i]][y+dy[i]]=='X') flag=1;
     79     if (mp[x][y]=='X')
     80         if (flag) return; else dfs(x,y+1,p);
     81     else
     82     {
     83         dfs(x,y+1,p);
     84         if (!flag)
     85         {
     86             mp[x][y]='X';
     87             dfs(x,y+1,-p);
     88             mp[x][y]='.';
     89         }
     90     }
     91 }
     92 int main(){
     93     int cas=0;
     94     while (~scanf("%d %d",&n,&m)){
     95         clr(mp,0); ans=0;
     96         rep(i,1,n) scanf("%s",mp[i]+1);
     97         dfs(1,1,1);
     98         printf("Case #%d: %d
    ",++cas,ans);
     99     }
    100 }
    View Code
  • 相关阅读:
    安装tomcat8过程记录
    epoll监听多文件描述符时调度顺序研究
    线程间通信之eventfd
    webstorm常用快捷键
    修改linux镜像源的方法
    如何使用《UNIX 网络编程》一书中的源码
    SSL的作用与目前主流的使用场景介绍
    SSL相关知识点架构整理
    SSL的发展历史
    实验室项目debug汇总
  • 原文地址:https://www.cnblogs.com/rpSebastian/p/5788009.html
Copyright © 2020-2023  润新知