Luogu P2258 [NOIP2014] 子矩阵(枚举+背包dp)
题目链接:https://www.luogu.com.cn/problem/P2258
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=21,MAXX=1<<29; 4 int n,m,r,c,a[N][N],lj[N],ins[N],dp[N][N],ans; 5 bool vis[N]; 6 7 inline int re_ad() { 8 char ch=getchar(); int x=0,f=1; 9 while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); } 10 while('0'<=ch && ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 11 return x*f; 12 } 13 14 inline int dabs(int d) { return d>0?d:-d; } 15 16 inline void init() { 17 memset(ins,0,sizeof(ins)); 18 for(int i=1;i<=n;++i) for(int j=2;j<=c;++j) ins[i]+=dabs(a[i][lj[j]]-a[i][lj[j-1]]); 19 } 20 21 inline int cal(int d,int e) { 22 int res=0; 23 for(int i=1;i<=c;++i) res+=dabs(a[d][lj[i]]-a[e][lj[i]]); 24 return res; 25 } 26 27 inline void print_test() { 28 printf("%d\n",ans); 29 for(int i=1;i<=c;++i) printf("%d ",lj[i]); puts(""); 30 for(int i=1;i<=n;++i) printf("%d ",ins[i]); puts(""); 31 for(int i=1;i<=n;++i) { 32 for(int j=1;j<=r;++j) printf("%d ",dp[i][j]); 33 puts(""); 34 } 35 puts(""); 36 } 37 38 inline void Solve() { 39 init(); 40 memset(dp,0x3f,sizeof(dp)); 41 for(int i=0;i<=n;++i) dp[i][1]=ins[i]; 42 for(int i=2;i<=n;++i) for(int j=2;j<=min(i,r);++j) { 43 for(int k=1;k<i;++k) dp[i][j]=min(dp[i][j],dp[k][j-1]+cal(k,i)+ins[i]); 44 } 45 for(int i=r;i<=n;++i) ans=min(ans,dp[i][r]); 46 // if(lj[1]==1 && lj[2]==3 && lj[3]==4) print_test(); 47 } 48 49 void search(int d,int x) { 50 if(d>c) { Solve(); return ; } 51 for(int i=x;i<=m;++i) if(!vis[i]) vis[i]=true,lj[d]=i,search(d+1,i+1),vis[i]=false; 52 } 53 54 int main() 55 { 56 n=re_ad(),m=re_ad(),r=re_ad(),c=re_ad(); 57 for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) a[i][j]=re_ad(); 58 ans=MAXX; 59 search(1,1); 60 printf("%d\n",ans); 61 return 0; 62 }