这个题目容易想到dp,dfs,dp状态太多,会mle加tle,dfs会tle。
那么就只能往图论上面想了,注意到一个事实,任何一个格子只能被两个木板覆盖。而且是一个横着放的木板,一个竖着放的木板,那么所有横着的木板都看成x集合的点,竖着放的点都看成y集合的点。而格子看成边,那么这就是一个二分图求最小覆盖的问题了。
上代码
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=59,inf=1e9; int n,m,ans; char a[maxn][maxn]; int chk[maxn][maxn],tt; void coll(int t,int s,int tmp) { for(int i=s;i<=m;i++) { if(a[t][i]=='.') break; chk[t][i]+=tmp; } } void colc(int t,int s,int tmp) { for(int i=t;i<=n;i++) { if(a[i][s]=='.') break; chk[i][s]+=tmp; } } void show() { for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) printf("%d",chk[i][j]); cout<<endl; } } int mm() { int aa=0,bb=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(!chk[i][j]&&a[i][j]=='*') { aa++; break; } } for(int i=1;i<=m;i++) { for(int j=1;j<=n;j++) if(!chk[j][i]&&a[j][i]=='*') { bb++; break; } } return min(aa,bb); } void dfs(int t,int s,int ret) { // if(++tt>8000000) return ; // show(); // cout<<ret<<endl<<endl; if(ret+mm()>=ans) return ; bool flag=true; for(int i=t;i<=n&&flag;i++) for(int j=1;j<=m&&flag;j++) if(!chk[i][j]&&a[i][j]=='*') { if(a[i+1][j]!='*') { coll(i,j,1); dfs(i,j,ret+1); coll(i,j,-1); } else if(a[i][j+1]!='*') { colc(i,j,1); dfs(i,j,ret+1); colc(i,j,-1); } else { coll(i,j,1); dfs(i,j,ret+1); coll(i,j,-1); colc(i,j,1); dfs(i,j,ret+1); colc(i,j,-1); } flag=false; } if(flag) ans=min(ret,ans); } int main() { // freopen("in.txt","r",stdin); while(scanf("%d %d",&n,&m)!=EOF) { tt=0; for(int i=1;i<=n;i++) scanf("%s",&a[i][1]); ans=inf; memset(chk,0,sizeof(chk)); dfs(1,1,0); cout<<ans<<endl; } return 0; }