zoukankan      html  css  js  c++  java
  • CF1102F Elongated Matrix(状压dp)

    传送门


    解题思路

    观察到n非常小,所以考虑状压dp。

    问题在于如何确定一个没有后效性的状态/状态转移方程。

    设dp[i][j]表示当前已经选择了的行的集合为i(一个二进制数),上一个选择的行是第j行的不考虑首行和末行的答案。

    首先转移可以通过提前预处理两行之间的代价优化到O(1)。而首行的选择实际上是有后效性的,所以通过枚举首行来消除这种后效性。

    于是过程为:枚举首行i-->枚举状态s-->枚举上一行选的行数j-->枚举下一行要选的行数k-->进行转移。

    转移方程为:(dp[step|(1<<k)][k]=max(dp[step|(1<<k)][k],min(dp[step][j],d[k][j])))

    对于每一个首行i来说,答案通过枚举末行j来求:(ans=max(ans,min(dp[m-1][j],c[j][i])))

    其中c数组也提前预处理,c[j][i]表示以第j行结尾第i行开头对答案的贡献。

    这样总复杂度为 (O(2^nn^3))

    注意对于每一个起点i,dp数组清空且初始化dp[1<<i][i]为正无穷。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<iomanip>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    template<class T>inline void read(T &x)
    {
        x=0;register char c=getchar();register bool f=0;
        while(!isdigit(c))f^=c=='-',c=getchar();
        while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
        if(f)x=-x;
    }
    template<class T>inline void print(T x)
    {
        if(x<0)putchar('-'),x=-x;
        if(x>9)print(x/10);
        putchar('0'+x%10);
    }
    const int maxn=10005;
    int n,m,a[20][maxn],dp[(1<<16)][17],d[20][20],c[20][20],ans;
    int main(){
    	ios::sync_with_stdio(false);
    	memset(d,0x3f,sizeof(d));
    	memset(c,0x3f,sizeof(c));
    	cin>>n>>m;
    	for(int i=0;i<n;i++){
    		for(int j=0;j<m;j++){
    			cin>>a[i][j];
    		}
    	} 
    	for(int i=0;i<n;i++){
    		for(int j=0;j<n;j++){
    			for(int k=0;k<m;k++){
    				d[i][j]=min(d[i][j],abs(a[i][k]-a[j][k]));
    			}
    		}
    	}
    	for(int i=0;i<n;i++){
    		for(int j=0;j<n;j++){
    			for(int k=0;k<m-1;k++){
    				c[i][j]=min(c[i][j],abs(a[i][k]-a[j][k+1]));
    			}
    		}
    	}
    	m=1<<n;
    	for(int i=0;i<n;i++){
    		memset(dp,0,sizeof(dp));
    		dp[1<<i][i]=0x3f3f3f3f;
    		for(int step=1;step<m;step++){
    			if(step&(1<<i))
    			for(int j=0;j<n;j++){
    				if(step&(1<<j)){
    					for(int k=0;k<n;k++){
    						if(step&(1<<k)) continue;
    						dp[step|(1<<k)][k]=max(dp[step|(1<<k)][k],min(dp[step][j],d[k][j]));
    					}
    				}
    			}
    		}
    		for(int j=0;j<n;j++){
    			ans=max(ans,min(dp[m-1][j],c[j][i]));
    		}
    	}
    	cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    在jQuery ajax中按钮button和submit的区别分析
    jQuery学习-打字游戏
    AndroidManifest.xml权限大全
    判断数据连接----小程序
    ADB常用的几个命令
    Android的ADB配置环境和adb指令使用
    读懂Android项目结构目录
    Android四大组件
    多态继承
    匿名内部类
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15389406.html
Copyright © 2011-2022 走看看