uva 10572 动态规划 最小表示法

题意:

给出一个n*m的棋盘,其中某些格子已被染色,现在要对剩余格子黑白染色,且满足:
1、黑白格子分别连通;
2、不存在2*2的单色正方形;
求方案数和任意一种方案;


以黑色为例转移如下:
If 左黑 && 上黑 Then 合并两个连通块
Else If 左白 && 上白 Then 形成新的连通块
Else If 左黑 && 上白 Then 和左边的合并
Else If 左白 && 上黑 Then 和上边的合并
If 左黑 && 上黑 && 左上黑 Then 形成2x2的格子,非法

If 最后一格 && 左白 && 上白 && 左上黑 Then 不连通,非法
If 上白 && 轮廓线上没有和上边相连的格子
If 轮廓线上有白色的格子 Then 不连通, 非法
If 当前格不是最后两格 Then 非法
(因为如果剩下格子有白色,不连通 剩下格子全黑色,必然有2x2的黑色格子)

最后对所有状态判断一下最多只能存在两个连通块
至于输出一个方案的话只要每次记录这个状态是从哪转来的,另外开两个数组记录前驱和当前颜色就好了

 

 

const int HashSize = 30007;
struct Hash {
    int chart[HashSize] ,pre[HashSize], sz;
    int state1[HashSize],state2[HashSize],leftUp[HashSize],col[HashSize];
    int stat1[HashSize],stat2[HashSize],lefUp[HashSize];
    void clear() {
        sz = 0;
        memset(chart, -1, sizeof(chart));
    }
    inline void push(int sta1,int sta2, int leftup, int color,int s1,int s2,int lp) {
        int x = s1 % HashSize;
        for (int it = chart[x] ; it != -1 ; it = pre[it]) {
            if (state1[it] == sta1 &&state2[it] == sta2 && leftUp[it] == leftup&&col[it]==color
                && stat1[it]==s1 && stat2[it]==s2 &&lefUp[it]==lp) {
                return ;
            }
        }
        state1[sz] = sta1;  state2[sz] = sta2;  leftUp[sz]=leftup; col[sz]=color;
        stat1[sz]=s1; stat2[sz]=s2; lefUp[sz]=lp;
        pre[sz] = chart[x]; chart[x] = sz ++;
    }
    int find(int &sta1,int &sta2, int &leftup) {
        int x = sta1 % HashSize;
        for (int it = chart[x] ; it != -1 ; it = pre[it]) {
            if (stat1[it] == sta1 &&stat2[it] == sta2 && lefUp[it] == leftup) {
                sta1=state1[it];    sta2=state2[it];    leftup=leftUp[it];
                return col[it];
            }
        }
    }
} H[8][8];

struct HashMap {
    int chart[HashSize] ,pre[HashSize], sz;
    int state1[HashSize],state2[HashSize],leftUp[HashSize];
    long long dp[HashSize];
    void clear() {
        sz = 0;
        memset(chart, -1, sizeof(chart));
    }
    inline void push(int sta1,int sta2, int leftup, long long val) {
        int x = sta1 % HashSize;
        for (int it = chart[x] ; it != -1 ; it = pre[it]) {
            if (state1[it] == sta1 &&state2[it] == sta2 && leftUp[it] == leftup) {
                dp[it] += val;
                return ;
            }
        }
        state1[sz] = sta1;  state2[sz] = sta2;  leftUp[sz]=leftup;
        dp[sz] = val;
        pre[sz] = chart[x]; chart[x] = sz ++;
    }
} HM[2];

int maze[15][15];
int code1[15], code2[15];
int Bin[15];
HashMap *src = HM;
HashMap *des = HM + 1;
long long ret;
inline bool check(int sta) {
    while(sta) {
        if((sta&7) > 1) return false;
        sta >>= 3;
    }
    return true;
}
inline void decode(int *code,int m,int sta) {
    for (int it = 0 ; it < m ; it ++) {
        code[it] = sta & 7;
        sta >>= 3;
    }
}
inline int encode(int *code,int m) {
    int sta = 0;
    int cnt = 1;
    memset(Bin , -1 , sizeof(Bin));
    for (int it = m - 1 ; it >= 0 ; it --) {
        if(code[it] == 0) {
            sta <<= 3;
        } else {
            if(Bin[ code[it] ] < 0) Bin[ code[it] ] = cnt ++;
            code[it] = Bin[ code[it] ];
            sta <<= 3;
            sta |= code[it];
        }
    }
    return sta;
}
void getgrid1(int i, int j, int n, int m, int sta1, int sta2, int leftup, long long val) {//
    decode(code1, m, sta1);
    int up1 = (i == 0) ? 0 : code1[j];
    int left1 = (j == 0) ? 0 : code1[j-1];
    if(up1 == 0 && left1 == 0) {
        code1[j] = 7;
    } else if(up1==0|| left1==0) {
        code1[j] = up1 + left1;
    } else if(up1 == left1) {
        code1[j] = left1;
    } else {
        for (int it=0; it<m; it++) {
            if(code1[it] == up1) code1[it] = left1;
        }
    }
    decode(code2, m, sta2);
    int up2 = (i == 0) ? 0 : code2[j];
    int left2=(i==0)?0:code2[j-1];
    if(up2) {
        int c = 0, cc = 0;
        for (int it = 0 ; it < m ; it ++) {
            if(up2 == code2[it]) c ++;
            if(code2[it]) cc ++;
        }
        if(c == 1) {//上黑,且轮廓线上没有与之连通的
            if(cc > 1)  return;
            if(!(i==n-1&&j>=m-2))   return;
        }
    }
    code2[j] = 0;
    if(up2&&left2&&leftup==1)return;
    if(i==0||j==0||!(up1&&left1&&leftup==1)){
        int s1=encode(code1,m), s2=encode(code2,m), lp=up1>0?1:2;
        des->push(s1, s2, lp, val);
        H[i][j].push(sta1,sta2,leftup,1,s1,s2,lp);
    }
}
void getgrid2(int i, int j, int n, int m, int sta1, int sta2, int leftup, long long val) {//
    decode(code2, m, sta2);
    int up2 = (i == 0) ? 0 : code2[j];
    int left2 = (j == 0) ? 0 : code2[j-1];
    if(up2 == 0 && left2 == 0) {
        code2[j] = 7;
    } else if(up2==0|| left2==0) {
        code2[j] = up2 + left2;
    } else if(up2 == left2) {
        code2[j] = left2;
    } else {
        for (int it=0; it<m; it++) {
            if(code2[it] == up2) code2[it] = left2;
        }
    }
    decode(code1, m, sta1);
    int up1 = (i == 0) ? 0 : code1[j];
    int left1=(i==0)?0:code1[j-1];
    if(up1) {
        int c = 0, cc = 0;
        for (int it = 0 ; it < m ; it ++) {
            if(up1 == code1[it]) c ++;
            if(code1[it]) cc ++;
        }
        if(c == 1) {//上白,且轮廓线上没有与之连通的
            if(cc > 1)  return;
            if(!(i==n-1&&j>=m-2))   return;
        }
    }
    code1[j] = 0;
    if(up1&&left1&&leftup==2)return;
    if(i==0||j==0||!(up2&&left2&&leftup==2)){
        int s1=encode(code1,m), s2=encode(code2,m), lp=up2>0?2:1;
        des->push(s1, s2, lp, val);
        H[i][j].push(sta1,sta2,leftup,2,s1,s2,lp);
    }
}

void PlugDP(int n, int m) {
    src->clear();
    src->push(0, 0, 1, 1);
    ret = 0;
    for ( int i = 0 ; i < n ; i ++ ) {
        for ( int j = 0 ; j < m ; j ++ ) {
            des->clear();
            for ( int k = 0 ; k < src->sz ; k ++ ) {//1白2黑
                if(maze[i][j]!=2)   getgrid1(i, j, n, m, src->state1[k], src->state2[k], src->leftUp[k], src->dp[k]);
                if(maze[i][j]!=1)   getgrid2(i, j, n, m, src->state1[k], src->state2[k], src->leftUp[k], src->dp[k]);
            }
            swap(src, des);
        }
    }
    int t;
    for (int i = 0 ; i < src->sz ; i ++ ) {
        if ( check(src->state1[i])&&check(src->state2[i]) ) {t=i;ret += src->dp[i];}
    }
    cout<<ret<<endl;
    if(ret){
        int sta1=src->state1[t],sta2=src->state2[t],leftup=src->leftUp[t];
        string s[8];
        for(int i=n-1;i>=0;i--){
            s[i]="";
            int col;
            for(int j=m-1;j>=0;j--){
                col=H[i][j].find(sta1,sta2,leftup);
                if(col==1)s[i].insert(0,"o");
                else s[i]=s[i].insert(0,"#");
            }
        }
        for(int i=0;i<n;i++)
            cout<<s[i]<<endl;
    }
    cout<<endl;
}

int main()
{
    int T,n,m;
    string str="12345678910";
    cin>>T;
    T++;
    while(T--){
        cin>>n>>m;
        for(int i=0;i<n;i++){
            cin>>str;
            for(int j=0;j<m;j++){
                if(str[j]=='o')maze[i][j]=1;//1白2黑
                else if(str[j]=='#')maze[i][j]=2;
                else maze[i][j]=0;
                H[i][j].clear();
            }
        }
        PlugDP(n,m);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ts65213/p/3144100.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值