• [杂题]:group(状压DP+轮廓线)


    题目描述

      $pure$在玩一个战略类游戏。现在有一个士兵方阵,每行有若干士兵,每个士兵属于某个兵种。行的顺序不可改变,且每一行中士兵的顺序也不可改变。但由于每一行都有$C$个位置($C$不小于任一行的士兵数),她能够安排每行的士兵依次站在某几个位置上。
      对于每一个士兵,令其前后左右相邻四个位置上有$v$个和他种类相同的士兵,则$pure$会获得$v$的布阵分数。现在$pure$想知道她最多能够获得多少布阵分数。


    输入格式

    第一行包含两个整数$R,C$,分别表示行数,以及每一行的位置数。
    接下来$R$行,每行一个由大写字母构成的字符串,同一字母的士兵为同一种类。


    输出格式

    一行一个整数,表示$pure$能够获得的最高布阵分数。


    样例

    样例输入:

    2 5
    ABBCD
    AC

    样例输出:

    6


    数据范围与提示

    样例解释:

    布阵如下:

    ABBCD
    A__C_

    共获得$6$分。

    数据范围:

    对于$20\%$的数据,$Rleqslant 3,Cleqslant 4$;
    对于$40\%$的数据,$Rleqslant 16$;
    对于$100\%$的数据,$Rleqslant 128,Cleqslant 16$,字符串长度不超过$C$。


    题解

    我们可以只考虑左边和上边的格子,因为兵种一样是相互的,所以最后再乘$2$即可。

    先考虑暴力的状压,无非就是枚举上一行的状态,然后再枚举本行的状态,取$max$,时间复杂度是$Theta((C_C^{frac{C}{2}})^2 imes C imes R)$的。

    然后,我们发现,瓶颈就在于枚举所有的状态,所以我们可以利用轮廓线。

    如果你打过插头$DP$,这将非常好理解,枚举行变成了枚举单个格,能对其作出贡献的只有其左边和上边的格了。

    代码实现稍繁琐……

    时间复杂度:$Theta(2^C imes C imes R)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int r,c;
    char ch[20];
    int Map[150][20];
    int Mapl[100000][20],Mapr[100000][20];
    int dp[2][100000];
    bool now;
    int ans;
    int main()
    {
    	scanf("%d%d",&r,&c);
    	for(int i=1;i<=r;i++)
    	{
    		scanf("%s",ch+1);
    		Map[i][0]=strlen(ch+1);
    		for(int j=1;j<=Map[i][0];j++)
    			Map[i][j]=ch[j]-'A'+1;
    	}
    	memset(dp,-0x3f,sizeof(dp));
    	dp[0][0]=0;
    	for(int i=0;i<(1<<c);i++)
    	{
    		for(int j=2;j<=c+1;j++)
    			Mapl[i][j]=Mapl[i][j-1]+(i&(1<<(j-2))?1:0);
    		for(int j=c-1;j;j--)
    			Mapr[i][j]=Mapr[i][j+1]+(i&(1<<j)?1:0);
    	}
    	for(int i=1;i<=r;i++)
    	{
    		for(int j=1;j<=c;j++)
    		{
    			now^=1;
    			memset(dp[now],-0x3f,sizeof(dp[now]));
    			for(int k=0;k<(1<<c);k++)
    			{
    				if(Map[i][Mapl[k][j]+1])
    					dp[now][((((k>>j)<<1)|1)<<(j-1))|(k&((1<<(j-1))-1))]=max(dp[now][((((k>>j)<<1)|1)<<(j-1))|(k&((1<<(j-1))-1))],dp[!now][k]+(((k&(1<<j-2))?Map[i][Mapl[k][j]]:0)==Map[i][Mapl[k][j]+1])+(((k&(1<<j-1))?Map[i-1][Map[i-1][0]-Mapr[k][j]]:0)==Map[i][Mapl[k][j]+1]));
    				dp[now][((((k>>j)<<1)|0)<<(j-1))|(k&((1<<(j-1))-1))]=max(dp[now][((((k>>j)<<1)|0)<<(j-1))|(k&((1<<(j-1))-1))],dp[!now][k]);
    			}
    		}
    		for(int j=0;j<(1<<c);j++)
    			if(Mapl[j][c+1]!=Map[i][0])dp[now][j]=-0x3f3f3f3f;
    	}
    	for(int i=0;i<(1<<c);i++)
    		ans=max(ans,dp[now][i]);
    	printf("%d",(ans<<1));
    	return 0;
    }
    

    rp++

  • 相关阅读:
    vue使用elementui合并table
    使用layui框架导出table表为excel
    vue使用elementui框架,导出table表格为excel格式
    前台传数据给后台的几种方式
    uni.app图片同比例缩放
    我的博客
    【C语言】取16进制的每一位
    SharePoint Solution 是如何部署的呢 ???
    无效的数据被用来用作更新列表项 Invalid data has been used to update the list item. The field you are trying to update may be read only.
    SharePoint 判断用户在文件夹上是否有权限的方法
  • 原文地址:https://www.cnblogs.com/wzc521/p/11604073.html
Copyright © 2020-2023  润新知