D
至少装满型背包
每个东西有两个维度的体积,选一些东西,是的两个维度的体积和分别超过 x , y x,y x,y,问最少需要选多少个东西
这种至少装满,肯定不能把背包大小开到特大,这样虽然肯定能统计到所有情况,但是每次都枚举所有容积,复杂度太高了。
这个时候的正解是,既然我们只关心是否超过 x , y x,y x,y,可以只把背包大小开到 x , y x,y x,y,然后用刷表型 d p dp dp,把大于 x , y x,y x,y的值都映射到 x , y x,y x,y
最后 d p ( x , y ) dp(x,y) dp(x,y)相当于是存储了所有不小于 x , y x,y x,y的方案的最小代价
void solve(){
int n,x,y;
cin>>n>>x>>y;
vi a(n+1),b(n+1);
rep(i,1,n){
cin>>a[i];
cin>>b[i];
}
vvi dp(x+10,vi(y+10,1e18));
dp[0][0]=0;
rep(i,1,n){
vvi ndp(x+10,vi(y+10,1e18));
ndp=dp;
rep(j,0,x){
rep(k,0,y){
int jj=min(x,j+a[i]);
int kk=min(y,k+b[i]);
ndp[jj][kk]=min(dp[j][k]+1,ndp[jj][kk]);
}
}
swap(ndp,dp);
}
if(dp[x][y]<1e18)cout<<dp[x][y];
else cout<<-1;
}
E
爆搜染色
一个网格图,围出一个区域,需要包含所有村庄,问有多少种不同方案。
开始由于题干是从区域边界定义的,我被误导了,虽然想到了枚举,但是想的是枚举边界的边,最后判定是否围起来所有村庄。但这个显然不可做。
后面才发现可以直接对网格染色,16个格子,直接用一个 2 16 2^{16} 216的爆搜枚举所有染色情况。
然后题目的约束是围出一个区域,所以染色区域必须只有一个连通块;而且染色区域内部不能有空洞,这点可以通过对所有未染色的点跑BFS,判断能否走到网格边界。
void solve(){
vvi a(4,vi(4));
int tot=0;
rep(i,0,3){
rep(j,0,3){
cin>>a[i][j];
tot+=a[i][j];
}
}
vvi vis(4,vi(4));
int ans=0;
auto check=[&]()->bool{
vvi vis0(4,vi(4));
auto &&dfs0=[&](auto &&dfs0,int i,int j)->void{
vis0[i][j]=1;
rep(k,0,3){
int ii=i+dx[k],jj=j+dy[k];
if(ii<0||ii>3||jj<0||jj>3||vis0[ii][jj])continue;
if(vis[ii][jj]){
dfs0(dfs0,ii,jj);
}
}
};
int cnt=0;
rep(i,0,3){
rep(j,0,3){
if(!vis0[i][j]&&vis[i][j]){
dfs0(dfs0,i,j);
cnt++;
}
}
}
return cnt==1;
};
auto &&dfs=[&](auto &&dfs,int i,int j)->void{
if(i==4){
int cnt=0,out0=0,out=0;
auto &&check1=[&](int x,int y)->int{
queue<pii>q;
q.push({x,y});
vvi vis2(4,vi(4));
vis2[x][y]=1;
while(q.size()){
auto t=q.front();
q.pop();
int x=t.fi,y=t.se;
rep(i,0,3){
int xx=x+dx[i],yy=y+dy[i];
if(xx<0||xx>3||yy<0||yy>3){
return 1;
}
if(!vis[xx][yy]&&!vis2[xx][yy]){
vis2[xx][yy]=1;
q.push({xx,yy});
}
}
}
return 0;
};
if(!check())return;
rep(x,0,3){
rep(y,0,3){
if(vis[x][y]){
cnt+=a[x][y];
}
else{
out0++;
out+=check1(x,y);
}
}
}
if(cnt==tot&&out==out0){
ans++;
// cout<<out<<' '<<out0<<'\n';
// rep(i,0,3){
// rep(j,0,3){
// cout<<vis[i][j]<<' ';
// }
// cout<<'\n';
// }
}
return ;
}
vis[i][j]=1;
dfs(dfs,j==3?i+1:i,j==3?0:j+1);
vis[i][j]=0;
dfs(dfs,j==3?i+1:i,j==3?0:j+1);
};
dfs(dfs,0,0);
cout<<ans;
}