CSDN周赛 第12期 满分题解

目录

  • 1.豚鼠排名榜(枚举、字符串)
    • 题目
    • 题解
    • 代码
  • 2.字符串转换(正则表达式)
    • 题目
    • 题解
    • 代码
  • 3.蚂蚁家族(无向图连通性、遍历)
    • 题目
    • 题解
    • 代码
  • 4.小股炒股(枚举)
    • 题目
    • 题解
    • 扩展题解
    • 代码

1.豚鼠排名榜(枚举、字符串)

题目

已知字符A.B,C。每个字符都有自己的权值q。 现不知道权值q,只知道A,B,C的三次比较结果。

返回从小到大顺序的字符串,比较结果有冲突时返回“Impossible”。

题解

直接枚举会比较麻烦。
考虑首先将3次比较结果整理成一个字母小于另一个字母的形式,然后枚举顺序答案,从顺序答案中可以倒推出3个小于关系,检查输入的3个小于关系和倒推出的3个小于关系是否有冲突。

代码

#include 
#include 

using namespace std;

void solve(string s, char &ch1, char &ch2) {
    if (s[1] == '<') {
        ch1 = s[0];
        ch2 = s[2];
    } else {
        ch1 = s[2];
        ch2 = s[0];
    }
}

bool check(char a[2], char b[2]) {
    if (a[0] == b[1] && a[1] == b[0]) {
        return false;
    }
    return true;
}

std::string solution(std::string exp1, std::string exp2, std::string exp3) {
    std::string result;
    char ch[3][2];
    solve(exp1, ch[0][0], ch[0][1]);
    solve(exp2, ch[1][0], ch[1][1]);
    solve(exp3, ch[2][0], ch[2][1]);
    char r[3];
    for (r[0] = 'A'; r[0] <= 'C'; r[0]++) {
        for (r[1] = 'A'; r[1] <= 'C'; r[1]++) {
            if (r[0] == r[1])continue;
            for (r[2] = 'A'; r[2] <= 'C'; r[2]++) {
                if (r[0] == r[2] || r[1] == r[2])continue;
                char now[3][2];
                now[0][0] = r[0];
                now[0][1] = r[1];
                now[1][0] = r[0];
                now[1][1] = r[2];
                now[2][0] = r[1];
                now[2][1] = r[2];
                bool ok = true;
                for (int i = 0; i < 3; i++) {
                    for (int j = 0; j < 3; j++) {
                        if (!check(ch[i], now[j])) {
                            ok = false;
                            break;
                        }
                    }
                    if (!ok)break;
                }
                if (ok) {
                    return string("") + r[0] + r[1] + r[2];
                }
            }
        }
    }
    return "Impossible";
// TODO:
//return result;
}

int main() {
    std::string exp1;
    std::string exp2;
    std::string exp3;
    getline(std::cin, exp1);;
    getline(std::cin, exp2);;
    getline(std::cin, exp3);;
    std::string result = solution(exp1, exp2, exp3);
    std::cout << result << std::endl;
    return 0;
}

2.字符串转换(正则表达式)

题目

已知一个字符串a,b。 字符串b中包含数量不等的特殊符号“.”,“”(字符串存在没有特殊符号或者全由特殊符号组成的情况)。 “.”表示该字符可以变成任意字符,“ ”表示该字符的前一个字符可以变成任意多个。 现在我们想知道b可否通过特殊符号变成a。 a* 可以转化为a,aa,aaa,aaaa…

题解

类似正则表达式。
注意*表示该字符的前一个字符可以变成任意多个,但不能是0个,所以预处理复制一份再比较。
比赛时记不太清函数的意思,也忘了怎么表示完整匹配,所以开头结尾均设为#,保证必须完整匹配。

代码

package main

import "fmt"
import "regexp"

func solution(a string, b string) {
	var newb string
	var lst rune
	for _, ch := range []rune(b) {
		if ch == '*' {
			newb = string(append([]rune(newb), lst))
		}
		newb = string(append([]rune(newb), ch))
		lst = ch
	}
	b = newb
	// TODO: 请在此编写代码
	ok, _ := regexp.MatchString("#"+b+"#", "#"+a+"#")
	//ok, _ := regexp.MatchString(b, a)
	if ok {
		fmt.Println("yes")
	} else {
		fmt.Println("no")
	}
}

func main() {
	var a string
	var b string
	fmt.Scan(&a)
	fmt.Scan(&b)
	solution(a, b)
}

3.蚂蚁家族(无向图连通性、遍历)

题目

小蚂蚁群是一个庞大的群体,在这个蚂蚁群中有n只小蚂蚁 ,为了保证所有蚂蚁在消息传送的时候都能接收到消息,需要在他们之间建立通信关系。就是要求小蚂蚁都可以通过多只或者直接联系到其他人。 已知几条小蚂蚁之间有通信关系,请问还需要再新建至少多少条关系?

题解

n个点,m条无向边,检查最少需要加几条边,使所有点全部联通。答案也就是当前连通块数减1。
比赛时题目确实没给出点标号的数据范围,实际上题目数据中点编号会稍稍超出n

代码

package main

import "fmt"

var e [][]int
var vis []bool

func dfs(u int) {
	vis[u] = true
	for _, v := range e[u] {
		if vis[v] {
			continue
		}
		dfs(v)
	}
}
func solution(n int, m int, arr [][2]string) {
	// TODO: 请在此编写代码
	e = make([][]int, n+100)
	vis = make([]bool, n+100)
	mx := 0
	ids := make(map[int]bool)
	for _, ar := range arr {
		var u, v int
		fmt.Sscanf(ar[0], "%d", &u)
		fmt.Sscanf(ar[1], "%d", &v)
		if u > mx {
			mx = u
		}
		if v > mx {
			mx = v
		}
		ids[u] = true
		ids[v] = true
		//if u<=0||u>n||v<=0||v>n{
		// continue
		//}
		e[u] = append(e[u], v)
		e[v] = append(e[v], u)
	}
	if n > mx {
		mx = n
	}
	if n != mx {
		//panic(n)
	}
	var ans = n - len(ids) - 1
	for i := range ids {
		if vis[i] {
			continue
		}
		ans++
		dfs(i)
	}
	fmt.Print(ans)
}
func main() {
	var temp_arr [2]int
	for i := 0; i < 2; i++ {
		fmt.Scan(&temp_arr[i])
	}
	n := temp_arr[0]
	m := temp_arr[1]
	arr := make([][2]string, m)
	for i := 0; i < m; i++ {
		for j := 0; j < 2; j++ {
			fmt.Scan(&arr[i][j])
		}
	}
	solution(n, m, arr)
}

4.小股炒股(枚举)

题目

已知n天后的股票行情,现在已有的本金是m, 规定只能入手一次股票和抛售一次股票。 最大收益(含本金)是?

题解

印象中数据范围非常小(n<=1000),可以直接枚举那一天买入和卖出,计算最大收益,时间复杂度O(n^2)。
注意不一定只交易1股,可知总收益=股数 乘以 每股收益,所以买入时应该买尽可能多股。而股价差绝对值最大未必最优,比如:5元本金,5买10卖不如2买5卖。
理论上如果股价一直下跌,当天买当天卖不含本金收益为0是最大收益。

扩展题解

如果数据范围更大,可以求前缀最小值,然后枚举卖出日期,或求后缀最大值枚举买入日期,时间复杂度O(n)。

代码

#include 
#include 
#include 
#include 
#include

using namespace std;

int solution(int n, int m, std::vector<int> &vec) {
    int result;
// TODO:
    result = m;
    for (int i = 0; i < (int) vec.size(); i++) {
        for (int j = i + 1; j < (int) vec.size(); j++) {
            int x = m / vec[i];
            result = max(result, m - x * vec[i] + x * vec[j]);
        }
    }
    return result;
}

int main() {
    int n;
    int m;
    std::vector<int> vec;
    std::cin >> n;
    std::cin >> m;
    std::string line_0, token_0;
    getline(std::cin >> std::ws, line_0);
    std::stringstream tokens_0(line_0);
    while (std::getline(tokens_0, token_0, ' ')) {
        vec.push_back(std::stoi(token_0));
    }
    int result = solution(n, m, vec);
    std::cout << result << std::endl;
    return 0;
}

你可能感兴趣的:(ACM,算法,图论,正则表达式,acm竞赛,c++)