Connect


题目描述:

C. Connect

Time Limit: 5000ms

Memory Limit: 65536KB
64-bit integer IO format: %lld Java class name: Main

Submit Status PID: 39565

Connect

You are playing a solitaire puzzle called “Connect”, which uses several letter tiles.

There are R × C empty cells. For each i (1 ≤ i ≤ R), you must put a string si (1 ≤ |si| ≤ C) in the i-th row of the table, without changing the letter order. In other words, you choose an integer sequence {aj} such that 1 ≤ a1 < a2 < … < a|si| ≤ C , and put the j-th character of the string si in the aj-th column (1 ≤ j ≤ |si|).

For example, when C = 8 and si = “ICPC”, you can put si like followings.
I_C_P_C_
ICPC____
_IC___PC

‘_’ represents an empty cell.

For each non-empty cell x, you get a point equal to the number of adjacent cells which have the same character as x. Two cells are adjacent if they share an edge.

Calculate the maximum total point you can get.

Input

The first line contains two integers R and C (1 ≤ R ≤ 128, 1 ≤ C ≤ 16).

Then R lines follow, each of which contains si (1 ≤ |si| ≤ C). All characters of si are uppercase letters.

Output

Output the maximum total point in a line.

Sample Input 1
2 4
ACM
ICPC

Output for the Sample Input 1
2

Sample Input 2
2 9
PROBLEMF
CONNECT

Output for the Sample Input 2
6

Sample Input 3
4 16
INTERNATIONAL
COLLEGIATE
PROGRAMMING
CONTEST

Output for the Sample Input 3
18

题解:

其实是一个很简单的状压dp:
有一个很重要的特性,就是每个字符串必须全部放进去,并且顺序不能够改变,那么一横行其实用CXX就可以很快表示,但是如果一行一行的枚举,复杂度还是会超,我们模仿放格子,状压一层,发现下面那层可以从左边推出来是第几个,上面那层可以从后面推出来是第几个.这样就完全搞定了.

重点:

格子状压两种方法,放格子的方法转压一层的小技巧.
其实放格子不只可以状压一层,还记得今年网络赛的坑..

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int MAX_STA = (1<<16)+100;
const int tot = (1<<16);
const int MAX_N = 128 + 10;
const int MAX_M = 20;
int f[MAX_M][MAX_STA];
char str[MAX_N][MAX_M];
int slen[MAX_N];
int xiao[20];
int num[MAX_STA];
int n, m;

int change(int sta, int x, int y)
{
    int ans = 0;
    int nowsta = (xiao[y]&sta);
    int laststa = sta - nowsta;
    int nownum = num[nowsta];
    if(nownum>=slen[x])
        return -1;
    int lastnum = slen[x-1] - num[laststa];
    if(((1<<y)&sta) && str[x][nownum] == str[x-1][lastnum])
    {
        ans++;
    }
    if(y!=0)
    {
        if(((1<<(y-1))&sta) && str[x][nownum-1] == str[x][nownum])
            ans++;
    }
    return ans;
}

void pre()
{
    for(int i = 0; i<tot; i++)
    {
        num[i] = 0;
        for(int j = 0; j<16; j++)
        {
            if((1<<j)&i)
                num[i]++;
        }
    }
    xiao[0] = 0;
    for(int i = 1; i<16; i++)
    {
        xiao[i] = (xiao[i-1]|(1<<(i-1)));
    }
}
void solve()
{
    int key = (1<<m);
    memset(f, -1, sizeof(f));
    f[0][0] = 0;
    for(int i = 1; i<=n; i++)
    {
        for(int j = 0; j<m; j++)
        {
            for(int s = 0; s<key; s++)
            {
                if(f[j][s]==-1)
                    continue;
                int nxty = j+1;
                int tmp = f[j][s];
                int nxtS = (s&(~(1<<j)));
                f[nxty][nxtS] = max(f[nxty][nxtS], tmp);
                int add = change(s, i, j);
                if(add!=-1)
                {
                    nxtS = (s|((1<<j)));
                    f[nxty][nxtS] = max(f[nxty][nxtS], tmp+add);
                }
            }
        }
        for(int j = 0;j<m;j++)
        {
            for(int s = 0;s<key;s++)
                f[j][s] = -1;
        }
        for(int s = 0; s<key; s++)
        {
            if(f[m][s]!=-1)
            {
                if(num[s]==slen[i])
                    f[0][s] = f[m][s];
            }
        }
        for(int s = 0;s<key;s++)
            f[m][s] = -1;
//        if(i == 3)
//        {
//            for(int j = 0; j<key; j++)
//            {
//                if(f[i][0][j]!=-1)
//                {
//                    printf("s is %d  %d\n", j, f[i][0][j]);
//                }
//            }
//        }
    }
    int ans = 0;
    for(int s = 0; s<key; s++)
    {
        ans = max(ans, f[0][s]);
    }
    printf("%d\n", ans*2);
}

int main()
{
   // freopen("3Cin.txt", "r", stdin);
    //freopen("3Cout.txt", "w", stdout);
    pre();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        slen[0] = 0;
        for(int i = 1; i<=n; i++)
        {
            scanf("%s", str[i]);
            slen[i] = strlen(str[i]);
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值