华南农业大学算法分析与设计第一章题解


9715 相邻最大矩形面积

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

vector<vector<int>> getNear(vector<int>& nums){
    vector<vector<int>> ans(nums.size());
    stack<vector<int>> s;
    for(int i =0;i<nums.size();i++){
        while (!s.empty() && nums[s.top()[0]]>nums[i]){//如果栈顶元素比当前的检索元素要大,那么就结束它
            //检查左边元素和右边元素,设置答案
            vector<int> top =  s.top();
            s.pop();
            for(int j = 0;j<top.size();j++){//结算该列表中的元素
                int idx = top[j];
                //然后ans[i][0]就是左边离他最近的那个元素,是栈的下边
                //ans[i][1]就是右边离他最近的那个元素
                int left = s.empty()?-1:s.top().back();
                ans[idx].push_back(left);
                ans[idx].push_back(i);
            }
        }
        if(!s.empty() && nums[s.top()[0]] == nums[i]){
            s.top().push_back(i);
        }else{
            vector<int> v;
            v.push_back(i);
            s.push(v);
        }
    }
    while (!s.empty()){
        vector<int> v= s.top();
        s.pop();
        int left = s.empty()?-1:s.top().back();
        for(int i = 0;i<v.size();i++){
            ans[v[i]].push_back(left);
            ans[v[i]].push_back(nums.size());
        }
    }
    return ans;
}


int main(){
    int n;cin>>n;
    vector<int> v;
    for(int i = 0;i<n;i++){
        int x;cin>>x;
        v.push_back(x);
    }
    vector<vector<int>> near= getNear(v);
    int ans = 0;
    for(int i =0;i<near.size();i++){
        //cout<<i<<":"<<v[i]<<" "<<near[i][0]<<" "<<near[i][1]<<",ans:"<<v[i]*(near[i][1]-near[i][0]-1)<<endl;
        ans = std::max(ans,v[i]*(near[i][1]-near[i][0]-1));
    }
    cout<<ans<<endl;
    return 0;
}

9716.矩形的并

import java.util.*;

public class Main{

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        double[][] rectangles = new double[n][4];
        for (int i = 0; i < n; i++) {
            double x1 = scanner.nextDouble(),y1 = scanner.nextDouble(),x2 = scanner.nextDouble(),y2= scanner.nextDouble();
            rectangles[i][0] = x1;
            rectangles[i][1] = y1;
            rectangles[i][2] = x2;
            rectangles[i][3] = y2;
        }
        double ans = rectangleArea(rectangles);
        System.out.println(String.format("%.2f",ans));
    }

    public static int MOD = (int)1e9+7;
    public static double rectangleArea(double[][] rectangles) {
        //1.首先搞清楚rectangle是[x1,y1,x2,y2]
        //然后咱们把矩形按照x进行排序,从小到大,先把x拿出来
        double ans = 0;
        List<Double> xes = new ArrayList<>();
        for (double[] rectangle : rectangles) {
            xes.add(rectangle[0]);
            xes.add(rectangle[2]);
        }
        Collections.sort(xes);
        for(int i = 1;i<xes.size();i++){
            //2.计算出宽度,取出端点
            double front = xes.get(i-1);//线段的起始端点
            double backend = xes.get(i);//线段的结束端点
            double len = backend-front;
            if(len == 0){
                continue;//宽度为0,没有计算价值
            }
            //然后计算所有在这个x范围的内矩形,我们先把y给它给拿进来
            List<double[]> lines = new ArrayList<>();//这个代表着在区间里面,所有的y线段
            for (double[] rectangle : rectangles) {
                //首先搞清楚rectangle是[x1,y1,x2,y2]
                //x1是左下角
                //x2是右上角
                //然后找出来所有和x有交集的
                if(rectangle[0]<= front && rectangle[2]>= backend){
                    //我们将这一段y给加入到候选区间中
                    lines.add(new double[]{rectangle[1],rectangle[3]});
                }
            }
            //然后就开始转化为了`区间合并问题了`
            if(lines.size() == 0){
                continue;
            }
            double[][] intervals = lines.toArray(new double[0][]);
            //首先按照起点进行排序
            Arrays.sort(intervals, new Comparator<double[]>() {
                @Override
                public int compare(double[] o1, double[] o2) {
                    return (int)(o1[0]-o2[0]);
                }
            });
            long total = 0;
            double[] cur = intervals[0];
            for(int j = 0;j<intervals.length;j++){
                double[] next = intervals[j];
                if(cur[1] >= next[0]){
                    cur[1] = Math.max(cur[1],next[1]);
                }else{
                    total += cur[1] - cur[0];
                    cur = next;
                }
            }
            total += cur[1] - cur[0];
            ans += total*len;
        }
        return ans;
    }
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool cmp(double* o1,double* o2){
    if(o2[0] - o1[0] >0){
        return true;
    }
    return false;
}

double rectangleArea(vector<vector<double>>&rectangles){
    double ans=0;
    //首先对x进行排序
    vector<double> xes;
    //x1 y1 x2 y2
    for (int i = 0;i<rectangles.size();i++){
        xes.push_back(rectangles[i][0]);
        xes.push_back(rectangles[i][2]);
    }
    sort(xes.begin(),xes.end());//对x进行排序
    //然后计算出宽度
    for(int i = 1;i<xes.size();i++){
        double front = xes[i-1];
        double backend = xes[i];
        double len = backend - front;
        //然后计算这个区间上,存在的矩形的y轴的最大覆盖区间
        if(len == 0){
            continue;
        }
        vector<double*> lines;//存储y轴的线段
        //x1 y1 x2 y2
        for(int j = 0;j<rectangles.size();j++){
            if(front >= rectangles[j][0] && backend <= rectangles[j][2]){
                double* line = new double[2];
                line[0] = rectangles[j][1];
                line[1] = rectangles[j][3];
                //cout<<line[0]<<" "<<line[1]<<endl;
                lines.push_back(line);
            }
        }
        //然后对这些y线段进行排序
        if(lines.empty()){
            continue;
        }
        //转化为区间排序的问题,按照起点进行排序
        sort(lines.begin(),lines.end(), cmp);
        double total = 0;
        double* cur = lines[0];
        for(int j =0;j<lines.size();j++){
            //cout<<cur[0]<<" "<<cur[1]<<" ";
            double* next = lines[j];
            if(cur[1]>=next[0]){
                cur[1] = std::max(cur[1],next[1]);
            }else{
                total += (cur[1] - cur[0]);
                cur = next;
            }
        }
        //cout<<cur[0]<<" "<<cur[1]<<" ";
        total += (cur[1] - cur[0]);
        //cout<<len<<" "<<total<<endl;
        ans += (total*len);
        //dcout<<endl;
    }
    return ans;
}

int main() {
    int n;cin>>n;
    vector<vector<double>> rectangles;
    for (int i = 0; i < n; ++i){
        double x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        vector<double> v;
        v.push_back(x1);v.push_back(y1);v.push_back(x2);v.push_back(y2);
        rectangles.push_back(v);
    }
    double ans = rectangleArea(rectangles);
    printf("%.2lf",ans);
    return 0;
}

10345.前缀平均值

#include <iostream>
#include <vector>
#include <iomanip>
using namespace  std;

void solve_10375(vector<double>&nums){
    if(nums.size() == 0){
        return ;
    }
    int n = nums.size();
    //先求前缀和
    double* sum = new double[nums.size()+1];
    //base-case
    sum[0] = 0;
    for(int i = 1;i<n+1;i++){
        sum[i] = sum[i-1]+nums[i-1];
        cout<<fixed<<setprecision(2)<<(sum[i]/i)<<" ";
    }
}

int main() {
    ios::sync_with_stdio(false);
    int n ;cin>>n;
    vector<double> v;
    for (int i = 0; i < n; ++i){
        double num;cin>>num;
        v.push_back(num);
    }
    solve(v);
    return 0;
}

17086 字典序的全排列

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int id = 1;
int* book;
void backtrack(vector<int>&nums,vector<int>&track){
    if(nums.size() == track.size()){
        cout<<id<<" ";id++;
        for (const auto &item : track){
            cout<<item;
        }
        cout<<endl;
        return;
    }
    for(int i = 0;i<nums.size();i++){
        if(book[i] == 1){
            continue;
        }
        //做出选择
        track.push_back(nums[i]);
        book[i] = 1;
        //回溯递归
        backtrack(nums,track);
        //撤销选择
        book[i] = 0;
        track.pop_back();
    }
}

int main() {
    ios::sync_with_stdio(false);
    int n;cin>>n;
    string s;cin>>s;
    book = new int [n];
    vector<int> nums;
    for (int i = 0; i < n; ++i){
        nums.push_back(s[i]-'0');
        book[i] = 0;
    }
    sort(nums.begin(),nums.end());
    vector<int> track;
    backtrack(nums,track);
    return 0;
}

8593 最大覆盖问题

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

void solve(vector<int>& nums){
    if(nums.size() == 1){
        cout<<1<<endl;
        return;
    }
    int ans = INT32_MIN;
    int slow = nums.size()-1,fast = nums.size()-2;
    while (fast!=-1){
        while (fast!=-1 && nums[fast]<= abs(nums[slow]) ){
            fast--;
        }
        ans = std::max(ans,slow-fast);
        slow = fast;
    }
    cout<<ans<<endl;
}

int main(){
    int n;cin>>n;
    vector<int> nums;
    for (int i = 0; i < n; ++i){
        int x;cin>>x;
        nums.push_back(x);
    }
    solve(nums);
    return 0;
}
//备注:这道题之所以不用fast回滚的原因如下
//当fast == slow-1的时候,这时候就是一个base-case,如果nums[fast]>nums[slow],这时候成立,slow下一个位置是slow-1
//当fast > slow-1的时候,如果nums[fast]>nums[slow],那么我们可以知道nums[slow-1]<abs(nums[slow])
//那么也就是在[fast,slow]上,对于任意i元素,均有nums[i]<=abs(nums[slow])
//由于了加了绝对值,我们无法保证在[fast,slow-1]上的所有元素都满足nums[i]<=abs(nums[slow-1])
//因此还需要检索abs(nums[slow-1])与前边这些元素的情况,假如abs(nums[slow-1])比刚才的abs(nums[slow])都还要大,就证明abs(nums[slow-1])比[fast,slow-2]上的所有元素都要大,就可以复用刚才检测出来的元素

11075 强盗分赃

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

void solve(int n){
    long ans = 0;
    int flag = 0;
    for(long i = 255,j=0;;i+=255,j++){
        ans = 12*(i+j)+8+53*((i+1+j)/256);
        if(ans>n){
            break;
        }
        flag = 1;
        cout<<ans<<" ";
    }
    if(flag == 0){
        cout<<"impossible";
    }
    return;
}

int main(){
    int n;cin>>n;
    solve(n);
    return 0;
}

11076 浮点数的分数表达(优先做)

我的解法比较啰嗦,但是把三种情况都给讨论好了,按照这个思路是没有错的

#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <numeric>

using namespace std;
//可用快速幂技巧优化
long long myPow(long long x,int y){
    for(int i = 0;i<y;i++){
        x*=10;
    }
    return x;
}

long long GCD(long long  a,long long  b){
    return b>0?GCD(b,a%b):a;
}

int main(){
    string s;cin>>s;
    int slow = 2,fast = 2;
    //1.找到循环节
    while (fast!=s.size() && s[fast]!='('){
        fast++;
    }
    //如果数字里面没有循环节
    if(fast == s.size()){
        //这时候的话就是直接来
        fast--;
        slow = 2;
        int m = fast - slow;
        int powNor = myPow(10,m);
        long long tmp1 = 0;
        for(int left = slow ;left<=fast;left++){
            tmp1 = tmp1*10+(s[left]-'0');
        }
        long long gcd = GCD(tmp1, powNor);
        long long xUp = tmp1/gcd;
        long long xDown = powNor/gcd;
        cout<<xUp<<" "<<xDown<<endl;
        return 0;
    }
    fast--;
    if(s[fast] == '.'){
        //表示全部是循环节
        slow = fast+2;
        fast = s.size()-2;
        long tmp2 = 0;
        for(int left = slow;left<=fast;left++){
            tmp2 = tmp2*10+(s[left]-'0');
        }
        int m = fast - slow;
        long long powSec = myPow(10,m)-1;
        long long yUp = tmp2;
        long long yDown = powSec;
        long gcd = GCD(yUp,yDown);
        yUp /= gcd;
        yDown /= gcd;
        cout<< yUp<<" "<<yDown<<endl;
    }else{
        //这时候还要先把循环节前的数字给搞定
        int n = fast - slow;
        long long powNor = myPow(10,n);
        long tmp1 =0;
        for(int left = slow;left<=fast;left++){
            tmp1 = tmp1*10+(s[left]-'0');
        }
        //然后开始处理循环节部分
        slow = fast+2;
        fast = s.size()-2;
        int m = fast - slow;
        long tmp2=0;
        for(int left = slow;left <= fast;left++){
            tmp2 = tmp2*10+(s[left]-'0');
        }
        long long powSec = myPow(10,m)-1;
        long long gcd = GCD(tmp2,powSec);
        long long yUp = tmp2/gcd;
        long long yDown = powSec/gcd;
        long long ansUp = tmp1*yDown+yUp;
        long long ansDown = powNor*yDown;
        gcd = GCD(ansUp,ansDown);
        ansUp /= gcd;
        ansDown /= gcd;
        cout<<ansUp<<" "<<ansDown<<endl;
    }
    return 0;
}

17963 完美数

#include <iostream>

using namespace std;
//如果一个数的真约数之和等于这个自然数本身,则这个自然数就称为完美数。
//比如6就是一个完美数,而8却不是。
//如果2^n - 1是一个质数,那么,由公式N(n)=2^(n-1)*(2^n-1)算出的数一定是一个完美数。例如,
//当n=2时,2^2 - 1 = 3是一个质数,于是N(2)=2^(2-1)*(2^2-1)=2*3=6是一个完美数;当n=3时,2^3 - 1 = 7也是一个质数,
//N(3)=4*7=28是一个完美数;当n=5时,N(5)=496也是一个完美数。

long long myPow(long long x,long long y){
    long long ans =1;
    for(int i =0;i<y;i++){
        ans*= x;
    }
    return ans;
}

int main(){
    long long * a = new long long[8];
    a[0] = 2;a[1]=3;a[2]=5;a[3]=7;a[4]=13;a[5]=17;a[6]=19;a[7]=31;
    for(int i = 0;i<8;i++){
        long long tmp1 = myPow(2,a[i]-1);
        long long tmp2 = tmp1*2-1;
        long long ans = tmp1*tmp2;
        cout<<i+1<<" "<<ans<<endl;
    }
}

文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录