Codeforces 225C Barcode(矩阵上DP)

题目链接:http://codeforces.com/contest/225/problem/C

题目大意:

给出一个矩阵,只有两种字符'.'和'#',问最少修改多少个点才能让每一列的字符一致,且字符一致的连续的列的宽度在x和y之间。

解题思路:

先求出每列‘.’和'#'的前缀和,sum[i][0]表示前i列'#' 的前缀和,sum[i][1]表示前i列'.' 的前缀和 ,因为修改要求每列都保持一直,其实我们可以将每列都当成一个点来看,那样我们就相当于是在一维序列上操作了。

 dp[i][0]表示最后一列为'.'的最优解,dp[i][1]表示最后一列为'#'的最优解 。

那么我们可以得到状态转移方程:

dp[i+j][0]=min(dp[i+j][0],dp[i][1]+sum[i+j][0]-sum[i][0]),x=<j<=y,0<=i<=m
dp[i+j][1]=min(dp[i+j][1],dp[i][0]+sum[i+j][1]-sum[i][1]),x=<j<=y,0<=i<=m

其实很好理解,dp[i+j][0]表示第i+j列为'.',那么可以由相差为j的第i列为'#'的状态推导过来,同时要将i+1~j的'#'都变为'.'

dp[i+j][1]同理。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<string>
 6 #include<string.h>
 7 #include<cctype>
 8 #include<math.h>
 9 #include<stdlib.h>
10 #include<stack>
11 #include<queue>
12 #include<set>
13 #include<map>
14 #define lc(a) (a<<1)
15 #define rc(a) (a<<1|1)
16 #define MID(a,b) ((a+b)>>1)
17 #define fin(name)  freopen(name,"r",stdin)
18 #define fout(name) freopen(name,"w",stdout)
19 #define clr(arr,val) memset(arr,val,sizeof(arr))
20 #define _for(i,start,end) for(int i=start;i<=end;i++)  
21 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
22 using namespace std;
23 typedef long long LL;
24 const int N=3e3+5;
25 const LL INF64=1e18;
26 const int INF=0x3f3f3f3f;
27 const double eps=1e-10;
28 
29 int dp[N][2];  //dp[i][0]表示最后一列为'.'的最优解,dp[i][1]表示最后一列为'#'的最优解 
30 int sum[N][2]; //sum[i][0]表示前i列'#' 的前缀和,sum[i][1]表示前i列'.' 的前缀和 
31 
32 int main(){
33     memset(dp,0x3f,sizeof(dp));
34     FAST_IO;
35     int n,m,x,y;
36     cin>>n>>m>>x>>y;
37     for(int i=1;i<=n;i++){
38         for(int j=1;j<=m;j++){
39             char x;
40             cin>>x;
41             if(x=='#')
42                 sum[j][0]++;
43             else
44                 sum[j][1]++;
45         }
46     }    
47     for(int i=1;i<=m;i++){
48         sum[i][0]+=sum[i-1][0];
49         sum[i][1]+=sum[i-1][1];
50     }
51 
52     dp[0][0]=dp[0][1]=0;
53     for(int i=0;i<=m;i++){
54         for(int j=x;j<=y;j++){
55             dp[i+j][0]=min(dp[i+j][0],dp[i][1]+sum[i+j][0]-sum[i][0]);
56             dp[i+j][1]=min(dp[i+j][1],dp[i][0]+sum[i+j][1]-sum[i][1]);
57         }
58     }
59     cout<<min(dp[m][0],dp[m][1])<<endl;
60     return 0;
61 }

猜你喜欢

转载自www.cnblogs.com/fu3638/p/9131467.html