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 }

 

posted @ 2021-08-13 23:24  上官书房  阅读(32)  评论(0)    收藏  举报