标签:amp etc leetcode res 状压 匈牙利算法 预处理 表示 domino
很经典的题,但是好久没做这类有点忘了。。
经典状压dp做法:用S表示一行的状态,某位为1表示该位被占用,反之表示该位未被占用
dp[i][S]表示第i行状态为S时的最大覆盖数,那么枚举第i-1行的状态S‘,如果S,S‘都合法,那么此时可以求出S状态下最多可以放多少块砖
预处理出cnt[S1][S2]表示上一行是S1,下一行是S2情况下,S2上的最大填放数,填放策略:先放竖的再放横的
然后dp时对于两个状态就可以o(1)转移了
二分图做法:进行黑白染色,每个地板抽象成一个点,黑白格分成两部分
显然可以在相邻两个地板之间连边,如果是障碍物就不能连,匈牙利算法找下最大匹配即可
class Solution { public: int cnt[1<<8][1<<8]; int mp[100][100],block[100]; void prework(int m){ for(int S1=0;S1<(1<<m);S1++) for(int S2=0;S2<(1<<m);S2++){//上下状态为S1 S2时下放最多填放数量 int num=0,T=S2; for(int i=0;i<m;i++)//把竖的填了 if(!(S1>>i & 1) && (T>>i & 1))num++,T-=(1<<i); for(int i=0;i<m-1;i++) if((T>>i&1) && (T>>(i+1)&1)){ num++; i++; } cnt[S1][S2]=num; } } int dp[50][1<<8]; int domino(int n, int m, vector<vector<int>>& broken) { prework(m); for(auto v:broken)mp[v[0]][v[1]]=1; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(mp[i][j])block[i]|=(1<<j); memset(dp,-1,sizeof dp); for(int i=0;i<n;i++){ for(int S=0;S<(1<<m);S++){ int f=0; for(int j=0;j<m;j++) if(!(S>>j & 1) && mp[i][j])f=1; if(f)continue; int T=S-block[i];//状态S可以自由填放的格子 if(i==0) dp[i][S]=max(dp[i][S],cnt[(1<<m)-1][T]); else { for(int S2=0;S2<(1<<m);S2++) if(dp[i-1][S2]!=-1) dp[i][S]=max(dp[i][S],dp[i-1][S2]+cnt[S2][T]); } } } int res=0; for(int i=0;i<(1<<m);i++) res=max(res,dp[n-1][i]); return res; } };
标签:amp etc leetcode res 状压 匈牙利算法 预处理 表示 domino
原文地址:https://www.cnblogs.com/zsben991126/p/13039541.html