状压dp入门 hdu1565

在这里插入图片描述
思路:将数字转化为2进制,表示每一行被选的数字的情况,首先预处理哪些数字是可以取得的合法状态,因为上下行之间没有公共边,可以通过这一条件知道合法状态满足右移或左移以为后&运算的和为0,将所有哥发的存入数组中。
然后直接暴力三重循环,用数组f[i][j]表示前i行的第i行选取状态用j的二进制的表示的最大值,通过dp
更新数组,最后得到结果。

#include <bits/stdc++.h>
const int INF=0x3f3f3f3f;
const int maxn=1<<17;
using namespace std;
typedef long long ll;
int t[maxn];//可以取得合法状态
int a[22][22];
int f[22][maxn];
int add(int i,int x){
    
    
    int res=0;
    int cnt=1;
    while(x){
    
    
        if(x&1)
            res+=a[i][cnt];
        x=x>>1;
        cnt++;
    }
    return res;
}//计算第i行,x状态下的和

int main ()
{
    
    
    //freopen("D:\\input.txt", "r", stdin);
    //freopen("D:\\output.txt", "w", stdout);
	int n;
	while(cin>>n){
    
    
        int cnt=0;
        int sum=0;
        for(int i=0;i<(1<<n);i++)
            if((i&(i>>1))==0)
               t[++cnt]=i;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++){
    
    
            for(int j=1;j<=cnt;j++){
    
    
                int s=add(i,t[j]);//这一行
                for(int k=1;k<=cnt;k++){
    
    
                    if((t[j]&t[k])==0){
    
    
                        f[i][j]=max(f[i][j],f[i-1][k]+s);
                    }
                }
            }
        }
        int m=0;
        for(int i=1;i<=cnt;i++){
    
    
            m=max(f[n][i],m);
        }
        printf("%d\n",m);
	}
    return 0;
}


猜你喜欢

转载自blog.csdn.net/u011612364/article/details/103940442