1 条题解
-
0
/* 每一行有n个数,第i个数选为1不选为0,假设n=5,其中一个合法的方案如下: 1 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 如果表达以上状态,很容易想到设计状态如下: bool f[6][2][2][2][2][2] 但是n不确定,定义也不能确定(状态推导的代码也不好写) 正确的做法是用一个整数(它的二进制形式)表示一行的01串,具体如下: int f[6][32]; 1 0 0 0 1=17 -> f[1][17] 0 0 1 0 0=4 -> f[2][4] 1 0 0 0 0=16 -> f[3][16] 0 0 1 0 1=5 -> f[4][5] 1 0 0 0 0=16 -> f[5][16] 算法过程: 1、保存所有合法状态v存于s数组中。 状态v为合法状态的条件:就是v的二进制表示形式中不能有连续2个1 [v&(v<<1)==0] && [v&(v>>1)==0] 比如:n=7,v=37, v的二进制是 0100101, v<<1的二进制是: 1001010, v&(v<<1)的结果是:-------- 0000000 说明v没有连续的2个1,才能使得 v&(v<<1)的结果等于0 v的二进制是 0100101, v>>1的二进制是: 0010010, v&(v>>1)的结果是:-------- 0000000 也能说明v没有连续的2个1,才能使得 v&(v<<1)的结果等于0 2、f[i][v]:表示只考虑第1-第i行,且第i行的状态是v时能合法获取的最大值。 3、f[i][v]如何衔接f[i-1][x]?x是第i-1行的状态值。要想f[i]能继承f[i-1],必须v和x不冲突: [v&x==0] && [v&(x>>1)==0] && [v&(x<<1)==0] */ #include<bits/stdc++.h> using namespace std; int a[20][20]; int slen,s[1<<15]; int f[20][1<<15]; int main() { int n;scanf("%d",&n); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]); slen=0; for(int v=0;v<(1<<n);v++) if( !(v&(v>>1)) && !(v&(v<<1)) )s[++slen]=v;//保存合法状态 memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=slen;j++) { int t=0;for(int k=0;k<n;k++) if( (1<<k) & s[j] ) t+=a[i][k+1]; for(int k=1;k<=slen;k++) if( !(s[j] & (s[k]>>1)) && !(s[j] & (s[k]<<1)) && !(s[j]&s[k]) ) f[i][s[j]]=max(f[i][s[j]],t+f[i-1][s[k]]); } int ans=0;for(int i=1;i<=slen;i++)ans=max(ans,f[n][s[i]]); printf("%d\n",ans); return 0; }
- 1
信息
- ID
- 537
- 时间
- 1000ms
- 内存
- 16MiB
- 难度
- 6
- 标签
- 递交数
- 199
- 已通过
- 62
- 上传者