hdu1565 用搜索代替枚举找可能状态或者轮廓线解(较优),参考poj2411

这题用直接枚举是超时的,必须要用搜索来搜索出所有可能的状态,然后再进行枚举

这是较慢的做法

/*
方格取数,相邻格子的数不可取,问最多取到的和是什么 
有点类似炮兵布阵,先打出所有可能的状态,然后dp[i][j]表示前i行在状态v[j]下的最大和 
dp[i][j]由dp[i-1][t]推出,v[t]是和v[j]兼容的状态 
*/
#include<bits/stdc++.h>
using namespace std;
int mp[25][25],n,dp[21][200000];
int v[200000],tot;
vector<int>sum[25];//sum[i][j]表示第i行在状态v[j]下的和 
inline int legal(int j){
    if( j&(j<<1) )return false;
    return true;
}
inline int cal(int s,int k){//状态s对应的数值 
    int res=0;
    for(int i=1;i<=n;i++)
        if( s&(1<<(i-1)) )res+=mp[k][n-i+1]; 
        return res;
}
void init(){
    tot=0;
    for(int j=0;j<=(1<<n)-1;j++)
        if(legal(j))v[tot++]=j;
}

int main(){
    while(cin>>n){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)cin>>mp[i][j];
        init();
        memset(dp,0,sizeof dp);
        for(int i=0;i<tot;i++)
            dp[1][i]=cal(v[i],1);
            
        for(int i=2;i<=n;i++)
            for(int j=0;j<tot;j++){//枚举i行的状态 
                for(int k=0;k<tot;k++){//枚举k行的状态
                    if( v[k]&v[j] )continue; 
                    dp[i][j]=max(dp[i][j],dp[i-1][k]+cal(v[j],i));
                }
            }
        
        int ans=0;
        for(int i=0;i<tot;i++)
            ans=max(ans,dp[n][i]);
        printf("%d\n",ans);
    }
} 

 

posted on 2019-02-11 14:39  zsben  阅读(171)  评论(0编辑  收藏  举报

导航