题解

· · 题解

题意

一个 n\times m 的矩阵里,有 k 个位置有鱼。

可以放置若干个炸弹,每个炸弹可以炸到上下左右和本格五个格子,一个格子被炸后,鱼的数量会减一。

问最小需要多少个炸弹才能把全部鱼都炸掉。

分析

$a_i\le3$,显然可以对每个有鱼的格子内鱼的数量进行一个状压,一个四进制数 $s$,第 $x$ 位表示第 $x$ 个有鱼的格子的鱼的数量,$dp_s$ 表示从初始状态到状态 $s$ 所需要的炸弹的最少数量。 转移方程为 $dp_t=\min\{dp_s\}+1$,其中 $t$ 表示在 $s$ 状态上放一个炸弹,可以达到的状态。 ### 代码 ```cpp #include<bits/stdc++.h> using namespace std; const int dx[5]={0,0,0,1,-1},dy[5]={1,-1,0,0,0}; int n,m,k,s,x[11],y[11],c[11],vis[11],dp[1<<20],fish[1010][1010]; vector<pair<int,int>>v; int main(){ memset(dp,0x3f,sizeof dp),cin>>n>>m>>k; for(int i=1;i<=k;i++){ cin>>x[i]>>y[i]>>c[i],(s<<=2)|=c[i],fish[x[i]][y[i]]=i; for(int t=0;t<5;t++) if(x[i]+dx[t]>0&&y[i]+dy[t]>0&&x[i]+dx[t]<=n&&y[i]+dy[t]<=m) v.push_back({x[i]+dx[t],y[i]+dy[t]}); }dp[s]=0,sort(v.begin(),v.end()),unique(v.begin(),v.end()); for(int i=s;i;i--){ memset(vis,0,sizeof vis); for(int j=k,tmp=i;j;j--){ if(tmp&3)vis[j]=1; if((tmp&3)>c[j])goto A; tmp>>=2; }for(auto[x,y]:v){ int ii=i; for(int t=0;t<5;t++){ int tmp=fish[x+dx[t]][y+dy[t]]; if(vis[tmp])ii-=(1<<(k-tmp<<1)); }dp[ii]=min(dp[ii],dp[i]+1); }A:; }return cout<<dp[0],0; } ```