刷栏杆Painting Fence(贪心|分治)
最开始的想法:每次迭代都进行一次刷栏杆的操作,贪心选择目的为刷到更多块,因此对比横刷和竖刷一次能刷的块个数。接着对如果栏杆底部出现分隔(不再连续)则分治。此做法部分正确,贪心选择结果不是全局最优解。
#include<iostream>
#include<vector>
using namespace std;
bool isEmpty(vector<int>h, int left, int right) {
for (int i = left; i <= right; i++)
if (h[i] > 0) return 0;
return 1;
}
//{lenth,left,right}
vector<int> findMaxRaw(vector<int> h, int left, int right) {
int i = left;
while (h[i] <= 0) i++;
vector<int> result{ 1,i,i };
for (int j = i+1; j <= right; j++) {
if (h[j] <= 0) break;
else {
if (j - i + 1 > result[0]) {
result[0] = j - i + 1;
result[1] = i;
result[2] = j;
}
}
}
return result;
}
int solution(vector<int> h, int left, int right) {
if (isEmpty(h, left, right)) return 0;
vector<int> maxraw=findMaxRaw(h, left, right);
vector<int> maxcol{ 0,-1 };
//handle
for(int i=left;i<=right;i++)
if (h[i] > maxcol[0]) {
maxcol[0] = h[i];
maxcol[1] = i;
}
if (maxraw[0] >= maxcol[0])
for (int i = maxraw[1]; i <= maxraw[2]; i++) h[i]--;
else h[maxcol[1]] = 0;
//split and solve
int i = left;
while (i<=right && h[i] <= 0) i++;
int j = i;
int sum = 1;
while (i<=right && j <= right) {
if (j == right) {
sum += solution(h, i, j);
break;
}
if (h[j + 1] <= 0) {
sum += solution(h, i, j);
i = j + 1;
while (i <= right && h[i] <= 0) i++;
j = i;
}
else j++;
}
return sum;
}
int main() {
int n;
cin >> n;
vector<int> h(n);
for (int i = 0; i < n; i++) cin >> h[i];
cout << solution(h, 0, h.size() - 1);
return 0;
}
正确做法:每次迭代选择若干次横刷或者若干次竖刷。贪心选择是本次迭代进行的最少刷栏杆次数。横刷则先从底部刷至出现分隔,分治。竖刷则次数为本次迭代栏杆数。
#include<iostream>
#include<vector>
using namespace std;
bool isEmpty(vector<int>h, int left, int right) {
for (int i = left; i <= right; i++)
if (h[i] > 0) return 0;
return 1;
}
int findmin(vector<int> h, int left, int right) {
int min = h[left];
for (int i = left + 1; i <= right; i++)
if (h[i] < min) min = h[i];
return min;
}
int solution(vector<int> h, int left, int right) {
if (left>right||isEmpty(h, left, right)) return 0;
if (left == right) return 1;
//vector<int> maxraw=findMaxRaw(h, left, right);
//vector<int> maxcol{ 0,-1 };
////handle
//for(int i=left;i<=right;i++)
// if (h[i] > maxcol[0]) {
// maxcol[0] = h[i];
// maxcol[1] = i;
// }
//if (maxraw[0] >= maxcol[0])
// for (int i = maxraw[1]; i <= maxraw[2]; i++) h[i]--;
//else h[maxcol[1]] = 0;
int sum = 0;
int row = findmin(h, left, right);
for (int i = left; i <= right; i++) h[i]-=row;
sum += row;
//split and solve
int i = left;
while (i<=right && h[i] <= 0) i++;
int j = i;
while (i<=right && j <= right) {
if (j == right) {
sum += solution(h, i, j);
break;
}
if (h[j + 1] <= 0) {
sum += solution(h, i, j);
i = j + 1;
while (i <= right && h[i] <= 0) i++;
j = i;
}
else j++;
}
if (sum <= right - left + 1) return sum;
else return right - left + 1;
}
int main() {
int n;
cin >> n;
vector<int> h(n);
for (int i = 0; i < n; i++) cin >> h[i];
cout << solution(h, 0, h.size() - 1);
}