sgu262:Symbol Recognition(状压DP)

题目大意:
       给出 k nm 01 矩阵 Si ,求出一个 1 尽量少的nm 01 矩阵 P ,满足k个矩阵与该矩阵的交互不相同,也就是说通过该矩阵能表示出给出的 k 个矩阵。

分析:
      这题有几个状压 DP 的思路,这里讲一个吧。
       假设我们将 Si P 的交定义为Qi,其编号为 Ti ,那么初始的时候交都为空,即 T1=T2=...=Tk=0Q1=Q2=...=Qk=
       枚举 P 当前的格子(x,y),假设有 Si,x,y=Sj,x,y=1 ,且 Qi=Qj ,那么当前格子放 1 的话,新的Qi依旧等于 Qj ,反之不等于。所以可以用最小表示搞出该格子放 1 后的T。然而 T 就是整个状压DP的状态。当 max{Ti}=k1 的时候,证明所有的 Ti 均不相同,也就是所有的 Qi 均不相同,此时的 P <script type="math/tex" id="MathJax-Element-5324">P</script>即为所求。

AC code:

#include <cstdio>
#include <cstring>
#include <map>
#define pii pair<int,int>
#define mp make_pair
using namespace std;

const int MAXK = 7;
const int MAXN = 11;
const int MAXS = 46660;
const int INF = 0x3f;

int n, m, k, s;
int g[MAXK][MAXN][MAXN];
int col[MAXN][MAXN];
int f[MAXS], fr[MAXS], fx[MAXS], fy[MAXS];
map<pii, int> S;
int ans[MAXN][MAXN];

void upd(int s, int x, int y)
{
    int ts = s, add = f[s], tot = 0, ns = 0;
    pii sta[MAXK];S.clear();
    for(int i = 0, j = 1; i < k; ++i, ts /= k, j *= k)
    {
        sta[i] = mp(ts%k, g[i][x][y]);
        if(!S.count(sta[i])) S[sta[i]] = tot++;
        ns += S[sta[i]]*j;
    }
    if(f[ns] > add+1)
    {
        f[ns] = add+1, fr[ns] = s;
        fx[ns] = x, fy[ns] = y;
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < k; ++i)
        for(int p = 0; p < n; ++p)
            for(int q = 0; q < m; ++q)
            {
                scanf("%1d", &g[i][p][q]);
                col[p][q] |= g[i][p][q];    
            }
    s = 1;
    for(int i = 0; i < k; ++i) s *= k;
    memset(f, INF, sizeof f);
    f[0] = 0;
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < m; ++j)
            if(col[i][j])
                for(int p = 0; p < s; ++p)
                    if(f[p] < INF)
                        upd(p, i, j);
    int end = 0;
    for(int i = k-1; i >= 0; --i)
        end = end*k+i;
    printf("%d\n", f[end]);
    int now = end;
    while(now)
    {
        ans[fx[now]][fy[now]] = 1;
        now = fr[now];
    }   
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < m; ++j)
            printf("%d", ans[i][j]);
        puts("");   
    }

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif  
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值