-
E - Maximum Sum
Gym - 101853E - 题意:choose a subset of the grid's cells, such that their summation is as maximal as possible.
- 限制: there are no two adjacent cells in that subset. Two cells are considered adjacent if they are horizontal, vertical, or diagonal neighbors.
- 随便选择一些数要求和最大
- 取数要求:不能上下、左右、主对角、副对角、直接相邻。
- n为16利用二进制枚举出一行合法状态,现在只考虑一行的限制之后左右相邻非法
- 所以二进制枚举一行中所有的状态合法的保存即可(枚举x时判断 x<<1&x与x>>1&x)
- dp数组第一维代表第几行第二维代表第几个单独一行合法的二进制状态。
- 后面的每一行的状态肯定是这里面的,但是会有列,对角线的要求所以三个for第一个for枚举接下来的行
- 第二个for枚举当前行选择的那个单独一行合法状态第三个for枚举上一行合法的状态对这两行进行列关系与对角关系的判断
- (当前行为c1上一行为c2,c1&c2||c1&(c2<<1)||c1&(c2>>1)这都是非法状态即上下相邻主对角相邻副对角相邻直接continue)
- 这样进行dp更新最大值即可。其中getsum是对相应的合法二进制状态对应到真实图上去取值求和
- ——by SDUT-QYN
-
#include<bits/stdc++.h> using namespace std; #define maxn 20 #define mxx (1<<16)+10 #define ll long long int t,n,mmp[maxn][maxn],sum; int dp[maxn][mxx],ans,m,c1,c2,one[mxx]; bool judge(int x) { if(x&(x<<1)) return false; if(x&(x>>1)) return false; return true; } int getsum(int row,int cur) { int ret=0; for(int i=0; i<n; i++) if(cur&(1<<i)) ret+=mmp[row][i]; return ret; } int main() { scanf("%d",&t); while(t--) { ans=sum=0; memset(one,0,sizeof(one)); memset(dp,0,sizeof(dp)); scanf("%d",&n); for(int i=0; i<n; i++) for(int j=0; j<n; j++) scanf("%d",&mmp[i][j]); m=(1<<n); for(int i=0; i<=m; i++) if(judge(i)) { one[sum]=i; dp[0][sum]=getsum(0,i); ans=max(ans,dp[0][sum]); sum++; } for(int r=1; r<n; r++) for(int i=0; i<sum; i++) { c1=one[i]; for(int j=0; j<sum; j++) { c2=one[j]; if(c1&c2||c1&(c2>>1)||c1&(c2<<1))continue; dp[r][i]=max(dp[r][i],dp[r-1][j]+getsum(r,c1)); ans=max(dp[r][i],ans); } } printf("%d\n",ans); } return 0; }
E - Maximum Sum -状压DP
最新推荐文章于 2020-08-01 20:54:54 发布