hdu 4285 circuits(插头DP多条回路无嵌套环)

circuits

Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 381    Accepted Submission(s): 128


Problem Description
  Given a map of N * M (2 <= N, M <= 12) , '.' means empty, '*' means walls. You need to build K circuits and no circuits could be nested in another. A circuit is a route connecting adjacent cells in a cell sequence, and also connect the first cell and the last cell. Each cell should be exactly in one circuit. How many ways do we have?

 

Input
  The first line of input has an integer T, number of cases.
  For each case:
  The first line has three integers N M K, as described above.
  Then the following N lines each has M characters, ‘.’ or ‘*’.
 

Output
  For each case output one lines.
  Each line is the answer % 1000000007 to the case.
 

Sample Input
  
  
2 4 4 1 **.. .... .... .... 4 4 1 .... .... .... ....
 

Sample Output
  
  
2 6
 

Source
 

Recommend
liuyiding
 
题意:给你一个方阵,有些地方能通过,有些地方不行,要求在方阵中方一些回路,覆盖所有可以通过的格子,这些回路不能相互包含。。。
分析:这题是插头DP的多条回路问题,不过这题的难点在于回路不能相互包含,这个问题我想了好久,没想到好的方法,想到增加插头数量。。。变得太复杂了
网上都说如果当前可以合并,必须满足包含这个回路的括号数为偶数,这个容易理解,如果是奇数的话,无论怎么做都不能使得回路不被包含。。。
还有这题有人说会爆内存要用map。。。我用了就爆内存了,没用就过了= =
而且速度还是比较快的,刷到前10了^_^
 代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int mm=100007;
const int mod=1000000007;
typedef long long LL;
struct hashTable
{
    int h[mm],s[mm],p[mm],t;
    LL v[mm][37];
    void push(int w,int j,LL val)
    {
        int i,id=w%mm;
        for(i=h[id];i>=0;i=p[i])
        if(s[i]==w)
        {
            v[i][j]+=val;
            if(v[i][j]>=mod)v[i][j]=v[i][j]%mod;
            return;
        }
        v[t][j]=val,s[t]=w,p[t]=h[id],h[id]=t++;
    }
    void clear()
    {
        while(t--)memset(v[t],0,sizeof(v[t]));
        t=0,memset(h,-1,sizeof(h));
    }
}f[2];
int i,j,k,g1,g2,n,m,K,t;
bool g[22][22];
char c;
bool ok(int s)
{
    if(s==1)return g[i+1][j];
    if(s==2)return g[i][j+1];
    return g[i+1][j]&&g[i][j+1];
}
bool can(int s)
{
    int sum=0,r=j;
    while(r--)
    {
        if((s&3)==1)++sum;
        if((s&3)==2)--sum;
        s>>=2;
    }
    return (sum&1)==0;
}
int Link(int s,int flag)
{
    int w,n=1,x=3<<(j<<1),a=(2-flag)<<(j<<1);
    while(n)
    {
        if(flag)x<<=2,a<<=2;
        else x>>=2,a>>=2;
        w=s&x;
        if(w)n+=(w==a)?1:-1;
    }
    return s^x;
}
void Work(int s,int k,LL val)
{
    int e,w=j<<1,x=(s>>w)&15;
    if(x==9)
    {
        if(k<K&&can(s))f[g2].push(s^(9<<w),k+1,val);
    }
    else if(!x)
    {
        if(ok(3))f[g2].push(s^(9<<w),k,val);
    }
    else if(!(x&3)||!(x&12))
    {
        if(x&3)e=0,x|=x<<2;
        else e=1,x|=x>>2;
        if(ok(1+e))f[g2].push(s,k,val);
        if(ok(1+!e))f[g2].push(s^(x<<w),k,val);
    }
    else if(x==6)f[g2].push(s^(x<<w),k,val);
    else f[g2].push(Link(s^(x<<w),x==5),k,val);
}
LL PlugDP()
{
    if(K>n*m/4)return 0;
    f[0].clear();
    f[0].push(0,0,1);
    for(g2=i=0;i<n;++i)
    {
        for(k=0;k<f[g2].t;++k)f[g2].s[k]<<=2;
        for(j=0;j<m;++j)
            if(g[i][j])for(g1=g2,g2=!g2,f[g2].clear(),k=0;k<f[g1].t;++k)
                for(int s=0;s<K;++s)
                    if(f[g1].v[k][s])Work(f[g1].s[k],s,f[g1].v[k][s]);
    }
    LL ret=0;
    for(k=0;k<f[g2].t;++k)
        if(!f[g2].s[k])ret+=f[g2].v[k][K];
    return ret;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&K);
        memset(g,0,sizeof(g));
        for(i=0;i<n;++i)
            for(j=0;j<m;++j)
                scanf(" %c",&c),g[i][j]=(c=='.');
        printf("%I64d\n",PlugDP());
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值