题目链接:欢度佳节
思路:首先我们观察到格子只有17个,则这可以让我们想到状态压缩(用二进制压缩状态),之后在借助dfs进行连通块遍历即可,时间复杂度o(x17)。
注意点:1.我们首先要将二进制上的每一位与图上的17个格子一一对应,这一点比较麻烦。
2.遍历连通块一般运用dfs。(套路)
3.一般而言,若n小于20,则可以考虑状态压缩。(套路)
所以,这题其实并不难,就是比较考验码力。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int number=10;
ll mapp[number][number];
ll t,al[number*10],n,sum;
ll ans,cnt,m;
bool ready[number*10][number*10];
ll y[number*10]={1,2,4,5,2,3,4,2,3,4,2,3,4,1,2,4,5};//映射
ll x[number*10]={1,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,5};//映射
ll num[number*10][number*10],p;//注意p要开全局变量,引用其实也可以
bool v[number*10][number*10];`
void dfs(int a,int b,int step){
if(a-1>=1&&v[a-1][b]==false&&((step>>mapp[a-1][b])&1)&&ready[a-1][b]&&p*6>=al[mapp[a-1][b]]){
cnt++;
v[a-1][b]=true;
p-=(al[mapp[a-1][b]]+5)/6;
dfs(a-1,b,step);
}
if(b+1<=5&&v[a][b+1]==false&&((step>>mapp[a][b+1])&1)&&ready[a][b+1]&&p*6>=al[mapp[a][b+1]]){
cnt++;
v[a][b+1]=true;
p-=(al[mapp[a][b+1]]+5)/6;
dfs(a,b+1,step);
}
if(a+1<=5&&v[a+1][b]==false&&((step>>mapp[a+1][b])&1)&&ready[a+1][b]&&p*6>=al[mapp[a+1][b]]){
cnt++;
v[a+1][b]=true;
p-=(al[mapp[a+1][b]]+5)/6;
dfs(a+1,b,step);
}
if(b-1>=1&&v[a][b-1]==false&&((step>>mapp[a][b-1])&1)&&ready[a][b-1]&&p*6>=al[mapp[a][b-1]]){
cnt++;
v[a][b-1]=true;
p-=(al[mapp[a][b-1]]+5)/6;
dfs(a,b-1,step);
}
}
bool check(int step){
int s=0,dig=step;
while(dig){ //计算二进制中有几个1
if(dig&1) s++;
dig/=2;
}
cnt=sum=0;
p=n;
memset(v,0,sizeof(v));
v[5][0]=true;
dfs(5,0,step); //遍历连通块
if(s!=cnt) return false;//判断是否合法
else return true;
}
int main(){
cin>>t;
for(int i=0;i<17;i++){
ready[x[i]][y[i]]=true;
}
for(int i=0;i<17;i++){
mapp[x[i]][y[i]]=i;
}
while(t--){
for(int i=0;i<17;i++){
cin>>al[i];
}
cin>>n;
ans=0;
for(int i=0;i<(1<<17);i++){//枚举状态压缩
if(check(i)) ans=max(ans,cnt); //判断状态是否合法,若合法则取最大值
}
cout<<ans<<endl;
}
}