您的位置:首页 > 其它

状态压缩-hdu1565和2018年全国多校算法寒假训练营练习比赛(第二场)F:德玛西亚万岁

2018-02-10 21:09 585 查看
hdu1565
题目:给你一个n*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。n≤20
思路:状态压缩+dp。dp[i][j]表示第i行,在j的状态下能取出的最大数和,则:dp[i][j]=sta[i][j]+max(dp[i-1][pre]),pre表示与j不冲突的前一个状态,sta[i][j]表示该行j状态下所取数的和。
优化:易发现,常规思路会超内存,且超时。先解决超时问题。发现对于一行来说,所取两个数不能相邻,所以所取的状态都是固定的,并不需要遍历所有状态。接着可以滚动数组优化内存。
ac代码:#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<utility>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long ll;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
const int maxn=1e5+5;

int n,dp[2][maxn],a[20][20],sta[maxn],num;
inline bool ok(int x){return !(x&(x>>1));}
int cal(int r,int x){
int ans=0,m=n-1;
while(x){
if(x&1) ans+=a[r][m];
x>>=1;--m;
}
return ans;
}
int main(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&a[i][j]);
mem(dp,0);num=0;
for(int i=0;i<(1<<n);i++) if(ok(i)) sta[num++]=i;
for(int i=0;i<num;i++) dp[0][i]=cal(0,sta[i]);
int cnt=0;
for(int i=1;i<n;i++){
for(int j=0;j<num;j++){
int sum=0;
for(int k=0;k<num;k++){
if(sta[j]&sta[k]) continue;
sum=max(sum,dp[cnt][k]);
}
dp[cnt^1][j]=sum+cal(i,sta[j]);
}
cnt^=1;
}
int ans=0;
for(int i=0;i<num;i++) ans=max(ans,dp[cnt][i]);
printf("%d\n",ans);
}
return 0;
}
2018年全国多校算法寒假训练营练习比赛(第二场)F:德玛西亚万岁
题目:接上面的条件,n*m的棋盘,位置为1的时候才可取,并且求总的选取方案数。n,m≤12
思路:状态压缩+dp。由于n较小,此题就省去了上面的优化步骤。
ac代码:#include<iostream>
#include<cstring>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long ll;
const int mod=1e8;
int maxn=1<<12;

int n,m,dp[2][1<<12],a[12][12];
bool ok(int r,int x){
if(x&(x<<1)) return false;
else{//此处要另判断状态x是否取了不该取的数,即位置为0的数
for(int i=0;i<m;i++){
if((x>>i)&1&&!a[r][m-1-i]) return false;
}
return true;
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
maxn=1<<m;
mem(dp,0);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]);
for(int i=0;i<maxn;i++) if(ok(0,i)) dp[0][i]=1;
int cnt=0;
for(int i=1;i<n;i++){
for(int j=0;j<maxn;j++){
dp[cnt^1][j]=0;
if(!ok(i,j)) continue;
int su
4000
m=0;
for(int k=0;k<maxn;k++){
if(j&k) continue;
sum+=dp[cnt][k];sum%=mod;
}
dp[cnt^1][j]=sum;
}
cnt^=1;
}
int ans=0;
for(int i=0;i<maxn;i++) ans=(ans+dp[cnt][i])%mod;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐