Loading

洛谷算法题

数字反转

https://www.luogu.com.cn/problem/P5705?contestId=152153

浮点数的使用

通过atoi函数可以把字符串转化为相对应的数字

image-20240722084250681

需要注意的是,本题输入的浮点数在实际解题中会出现有效值的问题

如:

image-20240722084300241

题解:https://www.luogu.com.cn/problem/solution/P5705(题解里有此问题的许多不同解,可以学习)

迪杰斯特拉算法

模板题:

https://www.luogu.com.cn/problem/P4779

最短路径问题可以用迪杰斯特拉算法,算法可以套用模版,将代码背诵下来直接写

#include <iostream>

#include <algorithm>

using namespace std;

const int  N = 1000;

#define INF 1000000001
int n,m;
int s;
int g[N][N]; //记录边
int len[N+1]; //从顶点到端点的长度
bool st[N+1]; //是否已访问点

void dijkstra(){
    for(int i=1;i<=n;i++) {
        st[i] = false;
        len[i] = INF;
    }
    st[s] = true;
    len[s] = 0;

    for(int i=0;i<n;i++){
        int id = s,mind = INF;
        for(int j=1;j<=n;j++){ //找到最短路径
            if (!st[j]&&len[j]<mind){
                mind = len[j];
                id = j;
            }
        }
        st[id] = true;
        for(int k=1;k<=n;k++){ //修改路径长度
            len[k] = min(len[k], len[id] + g[id][k]);
        }

    }

}

int main() {
    cin>>n>>m>>s;
    int ui,vi,wi;
    for(int i=0;i<=n;i++){
        for(int j=0;j<=n;j++){
            g[i][j] = INF;
        }
    }
    for(int i=0;i<m;i++){
        cin>>ui>>vi>>wi;
        g[ui][vi] = min(wi, g[ui][vi]) ;
    }
    dijkstra();
    for(int i=1;i<=n;i++){
        cout<<len[i]<<" ";
    }

}

背包问题

背包问题的求解通常使用动态规划方法。动态规划是一种将复杂问题分解为更简单子问题的方式。在背包问题中,动态规划可以用来计算每个可能的背包重量下的最大价值。

动态规划解决0-1背包问题的步骤如下:

  1. 定义一个二维数组dp[i][j],其中i表示可选的物品,j表示背包的容量。
  2. 初始化dp数组,当没有物品或者背包容量为0时,dp[i][j]均为0。
  3. 对于每种物品i和每个背包容量j,我们需要判断当前物品i是否可以放入背包中:
    • 如果当前物品i的重量大于背包容量j,则无法放入,此时dp[i][j] = dp[i-1][j]。
    • 否则,可以考虑放入当前物品i或者不放入,取两者的最大值,即dp[i][j] = max(dp[i-1][j], dp[i-1][j-物品i的重量] + 物品i的价值)。
  4. 最终,dp[n][m]即为问题的解,其中n表示物品的种类数,m表示背包的容量。
// <https://kamacoder.com/problempage.php?pid=1046>
#include<iostream>
#include<vector>

using namespace std;

int main(){
    vector<int> weight ;
    vector<int> value;
    int M,N;
    cin>>M>>N;
    int t;
    for(int i=0;i<M;i++){
         cin>>t;
        weight.push_back(t);
    }
    for(int i=0;i<M;i++){
        cin>>t;
       value.push_back(t);
    }
//	vector<vector<int>> dp(M,vector<int>(N+1,0));
    vector< vector<int> > dp(weight.size(), vector<int>(N + 1, 0));
    for(int i=weight[0];i<=N;i++){
        dp[0][i] = value[0];
    }

    for(int i=1;i<M;i++){
        for(int j=1;j<=N;j++){
            if(j<weight[i]) 	dp[i][j] = dp[i-1][j];
            else{
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
            }

        }
    }
    cout<<dp[M-1][N];
}

相关博客:

🔺https://github.com/youngyangyang04/leetcode-master/blob/master/problems/背包理论基础01背包-1.md

字符串排序

https://www.luogu.com.cn/problem/P1308?contestId=152172

模拟题

知识点: find函数应用,大小写转换

#include <iostream>
#include <string>
#include <algorithm>
const int MAX = 1001;
using namespace std;

int main(){
    string  s;

    string  A[MAX];
    int i=0;//记录数组位置
    string t;

   getline(cin,s); //待查字符串
    getline(cin,t);

    int pos = 0;
    //将字符串全部变为小写
    transform(s.begin(),s.end(),s.begin(),::towlower);
    transform(t.begin(),t.end(),t.begin(),::towlower);

    t =' '+t+' ';
    s=' '+s+' ';

    if (t.find(s)==string::npos){
        cout<<-1;
        return 0;
    } else{
        pos = t.find(s);
    }

    int acc = 0;

    int end = t.find(s);
    while (end!=string::npos){
        acc++;
        end = t.find(s,end+1);
    }
    cout<<acc<<" "<<pos;

//    for (int j = 0; j < size; ++j) {
////        if (j==0){//开始和结束时单独考虑
////
////        }
//        if (t.at(j)==' ') {
//            if (flag==1) {
//                end = j;
//                A[i++] = t.substr(begin+1,end-begin-1);//后面的为切割字符串的长度
////                flag = 0 ;
//                begin=j;
//            } else{
//                flag = 1;
//                begin = j;
//            }
//        }
////    }
//    bool f = false;
//    int acc = 0;
//
//    for (int j = 0; j < i; ++j) {
////        transform(A[j].begin(),A[j].end(),A[j].begin(),::towlower);
//
//        if (s==A[j]&&!f)
//        { //首次碰到
//            f = true;
//            acc++;
//            //计算首次出现的位置
//
//
//        } else if (s == A[j]&&f){
//            acc++;
//        }
//    }
//    if (f){
//        cout<<acc<<" "<<pos;
//    } else{
//        cout<<-1;
//    }

    return 0;

}

P1192 台阶问题

知识点: 递推斐波那契数列递推转非递推

递推方法会导致Time Limit Exceeded

#include <iostream>
using namespace std;

int times = 0;
int N,K;

void Fib(int stepLen,int n,int target){
    int then = n+stepLen;
    if (n+stepLen>target) return;
    else if (n+stepLen==target)times++;
    else{ //还没到目标台阶
        for (int i = 1; i <=K; ++i) {
            Fib(i,then,N);
        }
    }

}

int main(){

    cin>>N>>K;
    Fib(0,0,N);

   cout<<times%100003;

}

非递推(dp):

#include <iostream>
using namespace std;
const int MAXN = 1000001;
int  A[MAXN];
int N,K;

int main(){

    cin>>N>>K;
    A[0] = 1;
    A[1] = 1;
    for (int i = 2; i <=N ; ++i) {
        for (int j = 1; j<=K&&j<=i; ++j) {
            A[i] =(A[i] +A[i-j])%100003 ;

        }
    }
    cout<<A[N];

}

记住边计算边取模

P1111 修复公路

知识点:并查集的使用

#include <iostream>
#include <algorithm>

using namespace std;
const int MAXN = 1002;
const int MAXM = 100003;

struct Node{
    int x;
    int y;
    int t;
}node[MAXM];

int N,M;

int tree[MAXN];

int findFather(int a){
    if (a== tree[a])return a;
    else{
        return findFather(tree[a]);
    }
}
bool compare(Node a,Node b){
    return a.t<b.t;
}

int main(){
    int x,y,t;
    cin>>N>>M; //N为村庄数,M为道路数
    for (int i = 1; i <= N; ++i) {//初始化
        tree[i] = i;
    }
    for (int i = 1; i <= M; ++i) {
        cin>>x>>y>>t;
        if (x>y) swap(x,y);
        node[i].x = x;
        node[i].y = y;
        node[i].t = t;

    }
    sort(node+1,node+M+1, compare);

    int num = 0;
    int ans = 0;
    for (int i = 1; i <= M; ++i) {
        if (findFather(node[i].x)!= findFather(node[i].y)){//若祖先不同则进行合并
            num++;
            tree[findFather(node[i].y)] = findFather(node[i].x);
            ans = node[i].t;
        }
    }
    if (num == N-1) cout<<ans;
    else cout<<-1;

}

并查集的使用中,这一步很关键

image-20240722084630432

炸铁路问题

知识点:并查集Tarjan算法

https://www.luogu.com.cn/problem/P1656

我首先使用并查集暴力求解 ,样例通过但是提交之后全部WA

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXCity=151;
int n,m;

int City[MAXCity];
int City2[MAXCity];

struct Edge{
  int x;
  int y;
}edge[5001];
bool compare(Edge a,Edge b){
    if (a.x==b.x) return a.y<b.y;
    else return a.x<b.x;
}

int findFather(int t){
    if (City[t]==t) return t;
    else return findFather(City[t]);
}

bool isConnect(int x){//去掉第x行
    int ans = 0;
    for (int i = 1; i <= m ; ++i) {
        if (i==x) continue;
        int a = City2[edge[i].x];
        int b = City2[edge[i].y];
        if (a!=b){
            City2[edge[i].y] = findFather(a);
            ans++;
        }
    }
    if (ans==n-1) return true;
    else return false;
}

int main(){
    cin>>n>>m;
    for (int i = 1; i <=m; ++i) {
        cin>>edge[i].x>>edge[i].y;
    }
    sort(edge+1,edge+m+1,compare);

    for (int i = 1; i <=n ; ++i) {
        City[i] = i;
    }
    vector<int> result;
    for (int i = 1; i <=n ; ++i){
        for (int j = 1; j <=n ; ++j) {
            City2[j] = City[j];
        }

        if (!isConnect(i)) result.push_back(i);
    }
    for (int i = 0; i < result.size(); ++i) {
        int a1 = edge[result[i]].x;
        int a2 = edge[result[i]].y;
        cout<<a1<<" "<<a2;
        if (i!=result.size()-1) cout<<endl;
    }
}

后来发现在红框处添加 if (edge[i].x>edge[i].y) swap(edge[i].y,edge[i].x);

image-20240722084718035

结果通过了三个样例

image-20240722085059050

参考:

Tarjan算法:求解图的割点与桥(割边) - nullzx - 博客园

计数问题

#include <iostream>
#include <algorithm>

using namespace std;

int  main(){
    int n;
    char x;
    cin>>n>>x;
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        string r = to_string(i);
        if (r.find(x)!=string::npos){
           ans+= count(r.begin(), r.end(),x);
        }
    }
    cout<<ans;
    return 0;

}

🍎八皇后问题

[USACO1.5] 八皇后 Checker Challenge - 洛谷

知识点: DFS

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#define MAXN 40
using namespace std;
int n;
/*
 * 0行用来记录列
 * 1行记录主对角线平行方向的状态
 * 2行用来记录副对角线状态
 */
bool diag[MAXN][MAXN]; //用来记录状态
int ans[MAXN];
int sum = 0;
void queen(int line){ //line为行号
    if (line>n){
        sum++;
        if (sum>3) return;
        else{
            for (int i = 1; i <= n; ++i) {
                cout<<ans[i]<<" ";
            }
            cout<<endl;
        }
    }

    for (int i = 1; i <= n; ++i) {
        if (!diag[0][i]&&!diag[1][line+i]&&!diag[2][i-line+n]){
            ans[line] = i;
        diag[0][i] = true;
        diag[1][line+i] = true;
        diag[2][i-line+n] = true;
            queen(line+1);
            diag[0][i] = false;
            diag[1][line+i] = false;
            diag[2][i-line+n] = false;
        }
    }

}

int main(){
    cin>>n;
    //初始化数组
    for (int i = 0; i < MAXN; ++i) {
        for (int j = 0; j < MAXN; ++j) {
            diag[i][j] = false;
        }
    }
    queen(1);
    cout<<sum;

}

注意数组应开大一点,因为斜向会导致数组下标增大。

P3375 【模板】KMP

【模板】KMP - 洛谷

暴力求解代码:

//
// Created by CrisKey on 2024/2/27.
//

#include <iostream>
using  namespace std;

#define MAXN 1003
int kmp[MAXN];

//void cal_kmp(string s,int kmp[]){
//    int len = s.length();
//    int j = -1;
//
//    for (int i = 1; i < len; ++i) {
//        while(j==-1||)
//    }
//
//
//}
int main(){
    string s1,s2;
    cin>>s1>>s2;
    int begin = 0;
    int len1 = s1.length();
    int len2 = s2.length();
    int j = 0;
    for (int i = 0; i < len1; ++i) {
        if (s1[i]==s2[j]) j++;
        else{
            j=0;
            i= begin;

            begin = begin+1;
        }

        if (j==len2){
            cout<<begin+1<<endl;
            i=begin;
            begin = begin+1;

            j=0;
        }

    }
    cout<<0<<" ";
    int max = 0;

    for (int j = 1; j < len2; ++j) {
        int m = 0;
        int n = 1;
        int begin = n;
        while(n<=j){
            if (s2[m]==s2[n]){
                m++;
                n++;
            } else{
                m=0;
                n=begin+1;
                begin++;
            }
        }
        if (m>max)max = m;
        cout<<max<<" ";
        max = 0;
    }

}

参考:

字符串匹配的KMP算法 - 阮一峰的网络日志

Welcome - Luogu Spilopelia

设置精度可以使用:

cout << setprecision(20)<<sum+1; *//设置精度

同时需加入头文件:

#include**<iomanip>

posted @ 2024-07-22 08:55  我只有一天的回忆  阅读(17)  评论(0编辑  收藏  举报