HDU 4285 circuits[插头DP]

本文探讨了如何解决基于棋盘以外的路径和回路问题,提出了利用树的分治和树链剖分、DanceLinks算法来解决这类问题的方法,并以HDU4285《circuits》为例,详细阐述了如何求解给定条件下的电路回路方案数。通过模板代码展示了解题过程,为后续研究提供了实用的参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在只会做基于棋盘上的简单路径和简单回路问题, 非棋盘上的问题,和广义路径,很费劲,等学完树的分治和树链剖分、Dance Links,有余力在研究它。

HDU 4285circuits
求画规定条回路,不允许嵌套的方案数。

贴一份模板,便于以后复习。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL ;
const LL MOD = 1000000007LL ;
const int HASH = 99997 ;
const int STATE = 10001000 ;

int N, M ,K, cur ,num, tot ; // 已有环的个数
int code[20] , ch[20] , g[20][20] ;

void init() {
    char buf[20] ;
    tot = 0 ;
    memset(g ,0 ,sizeof(g)) ;
    for(int i=1; i<=N; i++) {
        scanf("%s" , buf + 1) ;
        for(int j=1; j<=M ;j++) {
            if(buf[j] == '.') g[i][j] = 1 ,tot++ ;
            else g[i][j] = 0 ;
        }
    }
}

LL encode(){
    memset(ch ,-1 ,sizeof(ch)) ;
    ch[0] = 0;
    LL ret = 0 , cnt = 1 ;
    for(int i=0; i<=M; i++) {
        if(ch[code[i]] == -1) ch[code[i]] = cnt++ ;
        ret = ret <<3 | ch[code[i]] ;
    }
    ret = ret<<6 | num ;
    return ret ;
}
void decode(LL s) {
    num = s&63 ;
    s>>=6 ;
    for(int i=M; i>=0; i--) {
        code[i] = s & 7 ;
        s >>= 3 ;
    }
}
void trans(int u,int v) {
    for(int i=0; i<=M; i++) if(code[i] == u) code[i] = v ;
}
struct Hash{
    int head[HASH] , next[STATE] , sz;
    LL f[STATE] , sta[STATE] ;
    void init() {
        sz = 0 ; memset(head, -1 ,sizeof(head)) ;
    }
    void push(LL s , LL val){
        int u = s % HASH ;
        for(int i=head[u] ; ~i ; i=next[i]) {
            if(sta[i] == s ) {
                f[i]  += val ;
                while(f[i] >= MOD) f[i] -= MOD ;
                return ;
            }
        }
        sta[sz] = s , f[sz] = val , next[sz] = head[u] , head[u] = sz ++ ;
    }
}dp[2];

void update(int j , LL s  , LL val){
    int _num = s & 63 ;
    if(j == M) s = ( (s>>3)&(~63) ) | _num ;
    dp[cur^1].push(s , val) ;
}

void dpblock(int i,int j){
    for(int k=0; k<dp[cur].sz; k++){
        update(j , dp[cur].sta[k] , dp[cur].f[k]) ;
    }
}

bool check(int p , int q) {
    int cnt = 0 ;
    for(int i=0; i<=p; i++) if(code[i]) {
        for(int j=q; j<=M; j++) if(code[j]) {
            if(code[i] == code[j]) cnt ++ ;
        }
    }
    return cnt % 2 == 0 ;
}

void dpblank(int i,int j) {
    for(int k=0; k<dp[cur].sz; k++){
        decode(dp[cur].sta[k]) ;
        int &P = code[j-1] , &Q = code[j] ;
        if(P && Q){
            if(P==Q){
                if(num < K && check(j-2 , j+1)) {
                    P = Q = 0 ;
                    num++ ;
                    update(j , encode() , dp[cur].f[k]) ;
                }
            }
            else{
                trans(P , Q) ;
                P = Q = 0 ;
                update(j , encode() ,dp[cur].f[k]) ;
            }
        }
        else if(P) {
            if(g[i+1][j]) update(j , dp[cur].sta[k] , dp[cur].f[k]) ;
            if(g[i][j+1]) {
                Q = P , P = 0;
                update(j , encode() , dp[cur].f[k]) ;
            }
        }
        else if(Q) {
            if(g[i][j+1]) update(j, dp[cur].sta[k] , dp[cur].f[k]) ;
            if(g[i+1][j]) {
                P = Q , Q = 0 ;
                update( j , encode() , dp[cur].f[k]);
            }
        }
        else {
            if(g[i][j+1] && g[i+1][j]) {
                P = Q = M + 2 ;
                update(j , encode() ,dp[cur].f[k]) ;
            }
        }
    }
}

int main()
{ 
    int T ;
    scanf("%d" ,&T) ;
    while(T--) {
        scanf("%d%d%d", &N, &M ,&K) ;
        init() ;
        if(tot/4 < K || K==0) {
            puts("0") ;
            continue ;
        }
        cur = 0;
        dp[cur].init() ;
        dp[cur].push(0 , 1) ;
        for(int i=1; i<=N; i++){
            for(int j=1; j<=M; j++) {
                dp[cur^1].init() ;
                if(g[i][j]) dpblank(i ,j );
                else dpblock(i , j) ;
                cur^=1 ;
            }
        }
        LL ans = 0;
        for(int k=0; k<dp[cur].sz; k++) {
            if( (dp[cur].sta[k] & 63) == K) ans += dp[cur].f[k] ;
        }
        while(ans >= MOD) ans -= MOD ;
        printf("%I64d\n" , ans) ;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值