You've got an n × m pixel picture. Each pixel can be white or black. Your task is to change the colors of as few pixels as possible to obtain a barcode picture.
A picture is a barcode if the following conditions are fulfilled:
- All pixels in each column are of the same color.
- The width of each monochrome vertical line is at least x and at most y pixels. In other words, if we group all neighbouring columns of the pixels with equal color, the size of each group can not be less than x or greater than y.
Input
The first line contains four space-separated integers n, m, x and y (1 ≤ n, m, x, y ≤ 1000; x ≤ y).
Then follow n lines, describing the original image. Each of these lines contains exactly m characters. Character "." represents a white pixel and "#" represents a black pixel. The picture description doesn't have any other characters besides "." and "#".
Output
In the first line print the minimum number of pixels to repaint. It is guaranteed that the answer exists.
Examples
input
Copy
6 5 1 2 ##.#. .###. ###.. #...# .##.# ###..
output
Copy
11
input
Copy
2 5 1 1 ##### .....
output
Copy
5
Note
In the first test sample the picture after changing some colors can looks as follows:
.##.. .##.. .##.. .##.. .##.. .##..
In the second test sample the picture after changing some colors can looks as follows:
.#.#. .#.#.
题意:
给你一个含有#号和.的图,要你把一列变成同一个符号,还有相同的列必须连续至少x个不超过y个.
思路:
这个题一看就是dp,可以设计状态dp[i][2]表示以第i列结尾的符号为#或.的最少改变次数.
由此可以想到dp[i+j]=min(dp[i+j][0/1],dp[i][1/0]+a[i+j]-a[i]/b[i+j]-b[i]);(i从0开始方便状态的设计),a[i]代表前i列改成相同#需要的次数,b[i]是改成'.'所需要的次数。
代码:
#include<iostream>
#include<cmath>
#include<cstring>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e3+100;
char mp[maxn][maxn];
int a[maxn],b[maxn];
int dp[maxn][2];
int main()
{
int n,m,x,y;
cin>>n>>m>>x>>y;
for(int i=1;i<=n;i++)
{
cin>>mp[i]+1;
}
for(int i=1;i<=m;i++)
{
int cnt1=0,cnt2=0;
for(int j=1;j<=n;j++)
{
if(mp[j][i]=='#')
{
cnt1++;
}
else
{
cnt2++;
}
}
a[i]=a[i-1]+cnt1;
b[i]=b[i-1]+cnt2;
}
memset(dp,INF,sizeof(dp));
dp[0][0]=dp[0][1]=0;
for(int i=0;i<m;i++)
{
for(int j=x;j<=y;j++)
{
if(i+j<=m)
{
dp[i+j][0]=min(dp[i+j][0],dp[i][1]+a[i+j]-a[i]);
dp[i+j][1]=min(dp[i+j][1],dp[i][0]+b[i+j]-b[i]);
}
}
}
int ans=min(dp[m][0],dp[m][1]);
cout<<ans<<endl;
return 0;
}
收获:状态设计对了,但转移的时候,没想到枚举所满足的列数即x<=j<=y。还可以设计其他状态,个人感觉这个最好理解。
dp还是太菜。