题意:n*m矩阵,每次操作让p*q大小的子矩阵-1(此子矩阵元素>0)
让你求得一个p,q使得操作次数最少
$n,mle 100$
首先,枚举p,q肯定是少不了
然后就有了一个剪枝
1、if(step>=ans) return;最优性剪枝
同时,为了使剪枝1更有效,我们要在最快的时间内减小ans
所以
2、p,q倒着枚举!
其次,可以发现,每一次操作会让矩阵减少p*q
因此,如果矩阵元素和不能整除p*q那就不用判断了
3、if(tot%(p*q))continue;可行性剪枝
4、if(tot/(p*q)>ans)continue;可行性剪枝
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define int long long #define olinr return #define _ 0 #define love_nmr 0 #define DB double inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } int ans; int n; int m; int tot; int ju[120][120]; int ls[120][120]; inline void dfs(int step,int lst,int x,int y) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ls[i][j]=ju[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int xx=i+x-1; int yy=j+y-1; int minn=0x7fffffff; if(xx>n||yy>m) break; for(int k=i;k<=xx;k++) for(int l=j;l<=yy;l++) if(!ls[k][l])goto girlfriend; else minn=min(minn,ls[k][l]); for(int k=i;k<=xx;k++) for(int l=j;l<=yy;l++) ls[k][l]-=minn; lst-=x*y*minn; step+=minn; if(step>=ans) return; girlfriend:; } if(!lst) { ans=min(ans,step); return; } } signed main() { n=read(); m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ju[i][j]=read(),ans+=ju[i][j]; tot=ans; for(int i=n;i>=1;i--) for(int j=m;j>=1;j--) { int c=i*j; if(tot%c||tot/c>=ans) continue; dfs(0,tot,i,j); } put(ans); olinr ~~(0^_^0)+love_nmr; }