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;
}


发布了409 篇原创文章 · 获赞 16 · 访问量 61万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览