题目:
###本题主要考察暴力,枚举,模拟
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int a[N],b[N];
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int num;cin>>num;
//样例个数循环
for(int i=1;i<=num;++i){
int n,k,mi=INT_MAX;
cin>>n>>k;
//颜色入数组
for(int j=1;j<=n;++j)cin>>a[j];
//60种颜色遍历
for(int j=1;j<=60;++j){
int cnt=0;
//保证数组初始化
for(int h=1;h<=n;++h)b[h]=a[h];
//每重案例 每种颜色 为每个房子遍历涂色
for(int h=1;h<=n;++h){
if(b[h]!=j){
//操作k区间
for(int z=h;z<=h+k-1;++z)b[z]=j;
//下一次要操作的房子
h+=k-1;
cnt++;
}
}
mi=min(mi,cnt);
}
cout<<mi<<'\n';
}
return 0;
}
整体思路:
- 颜色只有60种,可以将每一种情况对该k长度的区间的操作都遍历
- 循环j表示颜色,建两个数组只对第二个数组进行操作,每次用第一个数组给第二个数组初始化
- 用h表示该房子的下标,循环中的判断条件z<=h+k-1是因为该下标z也被操作了,所以要减去1,否则操作范围会有误(或者这样写也可以z<h+k),由于++h,每重循环都对下标加了1,所以下一次操作的房子一定要是h+=k-1,进入下一次循环的时候会自动的加上步长就是(h+=k)
- 每次都将次数与mi作比较,最终输出最小的次数
下面是第二种代码:(个人认为这份代码要优于上面的)
#include <bits/stdc++.h>
using namespace std;
int main() {
int t; cin >> t;
for (int i = 0, n, k; i < t; ++i) {
cin >> n >> k;
vector<int> arr(n);
unordered_set<int> s;
for (int j = 0; j < n; ++j) {
cin >> arr[j];
s.insert(arr[j]); //一个集合,防止重复记录
}
int ans = INT_MAX;
for(auto &x : s) {
int cnt = 0;
for(int j = 0; j < n; ++j) {
if(arr[j] == x) continue; //如果当前颜色和我要涂的颜色一样,那么跳过
cnt ++;
j += k - 1; //否则将k区间内的颜色全部涂该种颜色,由于上面有++j,这里要-1
}
ans = min(ans, cnt); //记录最小的就是答案
}
cout << ans << endl;
}
return 0;
}
这份代码用vector和unordered_set容器做了存储,大体上思路与上一份代码是一致的,这份代码最大的亮点就在于利用了unordered_set容器不重复的特性,无需将60种颜色都遍历(只遍历出现的颜色即可),小亮点在于他使用continue,避免了对数据的操作,直接使用下标来完成了上面代码繁琐的循环