[算法题] codefun2000 7.9日模拟赛

246 阅读1分钟

题目链接

前两题十分简单。最后一题在赛中想到了使用动态规划,但没有想到dp数组应该是含义。

第一题

思路

简单的模拟即可解决。

code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    // 处理输入
    int n;
    cin >> n;
    vector<vector<int>> vec(n, vector<int>(n));
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cin >> vec[i][j];
        }
    }
    
    int sum = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            sum += abs(vec[i][j] - vec[j][i]);
        }
    }
    cout << sum << endl;
    return 0;
}

第二题

思路

一个选择问题,选择比当前时间cur大的最小时间。

方法一是直接遍历,但这种方法需要计算与当前时间的时间差,处理起来稍有些麻烦。

方法二是利用本题时间模式的特点,先按字典序排序,然后再使用二分搜索法找到比当前时间大的最小时间。这里可以使用STL中的lower_bound()函数来完成二分搜索的过程。

code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    // 处理输入
    string cur;
    cin >> cur;
    int n;
    cin >> n;
    vector<string> vec(n);
    for(int i = 0; i < n; ++i) {
        cin >> vec[i];
    }
    
    sort(vec.begin(), vec.end());
    cout << *lower_bound(vec.begin(), vec.end(), cur) << endl;

    return 0;
}

第三题

思路

看到括号对匹配,第一个想法就是用栈,但实际并没有这么简单,例如对于{[[}这个括号对而言,使用栈就没有办法求出最小改变次数。再换个思路,本题的括号对其实就是字符串,并且要求最小修改,因此可以尝试一下动态规划。

dp数组的含义:
使括号对s在[i, j]范围内合法的最少修改次数为dp[i][j]。

递推公式:
使括号对s在[i, j]范围内合法的最少修改次数可能由两个地方得到,一是使[i+1, j-1]范围的括号对合法的最少修改次数,二是使[i, k]、[k+1, j]两个范围内的括号对合法的最少修改次数。

若s[i]与s[j]相同,则不需要修改:

dp[i][j]=min(dp[i+1][j1],dp[i+1][k]+dp[k+1][j])dp[i][j] = min(dp[i+1][j-1], dp[i+1][k]+dp[k+1][j])

若s[i]与s[j]相同不相同,且s[i]是左括号,则只需要修改s[j]:

dp[i][j]=min(dp[i+1][j1]+1,dp[i+1][k]+dp[k+1][j])dp[i][j] = min(dp[i+1][j-1]+1, dp[i+1][k]+dp[k+1][j])

若s[i]与s[j]相同不相同,且s[i]是左括号,则s[i]s[j]都需要修改:

dp[i][j]=min(dp[i+1][j1]+2,dp[i+1][k]+dp[k+1][j])dp[i][j] = min(dp[i+1][j-1]+2, dp[i+1][k]+dp[k+1][j])

初始化:
dp[i][j]都初始化为0就可以。

遍历顺序:

code

#include <bits/stdc++.h>
using namespace std;

int check(char x,char y){
    if(x=='['){
        if(y!=']') return 1;
            return 0;
    }
    if(x=='('){
        if(y!=')') return 1;
            return 0;
    }
    if(x=='{'){
        if(y!='}') return 1;
            return 0;
    }
    if(x=='<'){
	if(y!='>') return 1;
            return 0;
    }
    if(y!='>'&&y!=']'&&y!='}'&&y!=')') return 2;
    return 1;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    string str;
    cin >> str;
    int n = str.size();

    vector<vector<int>> dp(n, vector<int>(n,0));
	
    for(int len=2;len<=n;len+=2){
        for(int i=0;i<n-2;++i){
            int j=i+len-1;
            if(j>n) break;
            dp[i][j]=dp[i+1][j-1]+check(str[i],str[j]);
            for(int k=i+2;k<j;k+=2){
                dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k][j]);
            }
        }
    }
    printf("%d\n",dp[0][n-1]);
    return 0;
}

补充

1.本题的dp数组含义与递推公式与LC 回文串个数有相似之处。不同在于回文串必须是连续的,所以不需要考虑本题的递推公式中dp[i][k-1]+dp[k][j]的部分。

2.本题是尽可能少地修改原括号对,使得整个括号串匹配。若改为求尽可能少地添加括号,使这些括号匹配起来,应该怎么做?
这就是LC921
另外再补充LC1541