非常基础的一道状压dp
我们用二进制来表示每一行取数情况, 1 1 1表示取, 0 0 0表示不取
很容易得到状态转移方程:
f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i − 1 ] [ k ] + a n s [ i ] [ j ] ) ; f[i][j]=max(f[i][j],f[i-1][k]+ans[i][j]); f[i][j]=max(f[i][j],f[i−1][k]+ans[i][j]);当且仅当 j j j& k = = 0 k==0 k==0时
#include
#define M 150009
using namespace std;
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int f[25][M],ans[25][M],a[25][25],cnt,maxn,c[M],n,s[25];
void clear(){//多组数据,注意清空数组
cnt=maxn=0;
memset(a,0,sizeof(a));
memset(ans,0,sizeof(ans));
memset(f,0,sizeof(f));
}
signed main(){
while(~scanf("%d",&n)){
clear();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=read();
for(int i=0;i<(1<<n);i++) if((i&(i>>1))==0) c[++cnt]=i;//存储下每一种合法状态
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt;j++){
int x=c[j],tot=n;
while(x){
if(x&1) ans[i][j]+=a[i][tot];
tot--,x>>=1;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt;j++){
for(int k=1;k<=cnt;k++){
if((c[j]&c[k])!=0) continue;//注意括号
f[i][j]=max(f[i][j],f[i-1][k]+ans[i][j]);
if(i==n) maxn=max(maxn,f[i][j]);
}
}
}printf("%d\n",maxn);
}return 0;
}
显然直接bfs是不行的
那么我们用二进制来表示是否具有该钥匙的状态,每到一个地方更新状态即可
代码细节较多
#include
#define M 1509
using namespace std;
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
int n,m,t,ans;
bool vis[21][21][M];
char mp[49][49],s[40];
struct point{int x,y,step,key;}st;
bool check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]!='*') return 1;
return 0;
}
void bfs(){
queue<point>q;
memset(vis,0,sizeof(vis));
vis[st.x][st.y][st.key]=1;
st.key=st.step=0;
q.push(st);
point cur,nxt;
while(!q.empty()){
cur=q.front();
q.pop();
if(mp[cur.x][cur.y]=='^'){ans=cur.step;return;}
for(int i=0;i<4;i++){
nxt.x=cur.x+dx[i];
nxt.y=cur.y+dy[i];
nxt.key=cur.key;
if(check(nxt.x,nxt.y)){
nxt.step=cur.step+1;
if(nxt.step>=t) continue;
else if(mp[nxt.x][nxt.y]>='A'&&mp[nxt.x][nxt.y]<='Z'){
int temp=mp[nxt.x][nxt.y]-'A';
int nk=cur.key&1<<temp;
if(nk&&!vis[nxt.x][nxt.y][nxt.key]){
vis[nxt.x][nxt.y][nxt.key]=true;
q.push(nxt);
}
}
else if(mp[nxt.x][nxt.y]>='a'&&mp[nxt.x][nxt.y]<='z'){
int temp=mp[nxt.x][nxt.y]-'a';
nxt.key=cur.key|1<<temp;
if(!vis[nxt.x][nxt.y][nxt.key]){
vis[nxt.x][nxt.y][nxt.key]=true;
q.push(nxt);
}
}
else{
if(!vis[nxt.x][nxt.y][nxt.key]){
vis[nxt.x][nxt.y][nxt.key]=true;
q.push(nxt);
}
}
}
}
}ans=-1;return;
}
signed main(){
while(~scanf("%d%d%d",&n,&m,&t)){
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
mp[i][j]=s[j];
if(s[j]=='@') st.x=i,st.y=j;
}
}bfs(),printf("%d\n",ans);
}return 0;
}
一道经典的状压dp,细节较多
#include
#define int long long
using namespace std;
int n,m,s[100],ma[109],num[100],cnt,dp[101][101][110];
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
bool pd(int x){
if(x&(x<<1)) return 0;
if(x&(x<<2)) return 0;
return 1;
}
int num_one(int x){
int sum=0;
while(x){
if(x&1) sum++;
x=x>>1;
}return sum;
}
void init(){
for(int i=0;i<=(1<<m)-1;i++)
if(pd(i)){
s[cnt]=i;
num[cnt++]=num_one(i);
}
}
bool zjf(int x,int y){
if(x&y) return 0;
return 1;
}
int solve()
{
int ans=-100;
memset(dp,-1,sizeof(dp));
dp[0][0][0]=0;
for(int i=0;i<cnt;i++)
if(zjf(ma[1],s[i])){
dp[1][i][0]=num[i];
ans=max(ans,dp[1][i][0]);
}
for(int i=2;i<=n;i++)
for(int j=0;j<cnt;j++)
if(zjf(ma[i],s[j]))
for(int k=0;k<cnt;k++)
if(zjf(ma[i-1],s[k])&&(s[j]&s[k])==0){
int maxx=0;
for(int u=0;u<cnt;u++)
if(dp[i-1][k][u]!=-1&&zjf(ma[i-2],s[u])&&(s[u]&s[j])==0&&(s[u]&s[k])==0)
maxx=max(maxx,dp[i-1][k][u]);
dp[i][j][k]=max(maxx+num[j],dp[i][j][k]);
if(i==n) ans=max(ans,dp[i][j][k]);
}
return ans;
}
signed main(){
char ch;
n=read(),m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>ch;
if(ch=='H') ma[i]=ma[i]|(1<<(m-j));
}init();
cout<<solve()<<endl;
return 0;
}
}