数算选做

线性数据结构

中缀表达式的值

#include<cstdio>
#include<iostream>
#include<stack>
#include<cmath>

using namespace std;

int T;

bool isNumber(char x){
	if(x <= '9' && x >= '0') return true;
	return false;
}

string number(string ch){
	
	string str = "";
	while(isNumber(ch[0])){
		
		str.push_back(ch[0]);
		ch.erase(0, 1);
	}
	return str;
}

int prio(char x){
	if(x == '(' || x == ')') return 0;
	if(x == '+' || x == '-') return 1;
	if(x == '*' || x == '/') return 2;
	if(x == '^') return 3;
	return -1;
}

int strToNumber(string ch){
	
	int ans = 0, len = ch.length();
	for(int i = 0; i < len; ++i)
		ans = ans*10 + ch[i] - '0';
	return ans;
}

string suffix(string ch){
	
	stack<char> sig;
	string ans = "";
	while(ch != ""){
		
		if(ch[0]==' '){
			ch.erase(0, 1);
		}
		else if(isNumber(ch[0])){
			string num = number(ch);
			ans+=num+".";
			ch.erase(0, num.length());
		}
		else if(ch[0]=='-' && isNumber(ch[1])){
			ch.erase(0, 1);
			string num = number(ch);
			ans+="-"+num+'.';
			ch.erase(0, num.length());
		}
		else if(ch[0] == '('){
			sig.push('(');
			ch.erase(0, 1);
		}
		else if(ch[0] == ')'){
			while(sig.top() != '('){
				ans.push_back(sig.top());ans.push_back('.');
				sig.pop();
			}
			sig.pop();
			ch.erase(0, 1);
		}
		else{
			char now = ch[0];
			ch.erase(0, 1);
			while(!sig.empty() && prio(sig.top()) >= prio(now)){
				ans.push_back(sig.top());ans.push_back('.');
				sig.pop();
			}
			sig.push(now);
		}
	}
	while(!sig.empty()){
		
		ans.push_back(sig.top());ans.push_back('.');
		sig.pop();
	}
	return ans;
}

int solve(string ch){
	
	stack<int> num;
	while(ch != ""){
		
		if(isNumber(ch[0])){
			string str = number(ch);
			ch.erase(0, str.length()+1);
			num.push(strToNumber(str));
		}
		else if(ch[0] == '-' && isNumber(ch[1])){
			ch.erase(0, 1);
			string str = number(ch);
			ch.erase(0, str.length()+1);
			num.push(0-strToNumber(str));
		}
		else{
			char now = ch[0];ch.erase(0, 2);
			int num1 = num.top();num.pop();
			int num2 = num.top();num.pop();
			if(now == '+') num.push(num2+num1);
			if(now == '-') num.push(num2-num1);
			if(now == '*') num.push(num2*num1);
			if(now == '/') num.push(num2/num1);
			if(now == '^') num.push(pow(num2, num1));
		}
	}
	return num.top();
}

int main() {
	scanf("%d\n", &T);while(T--){
		string ch;
//		cin>>ch;
		getline(cin, ch);
//		cout<<suffix(ch)<<endl;
		cout<<solve(suffix(ch))<<endl;
	}
	return 0;
}

字符串

英语数字转换器

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

char c[10000];
int sgn=1, num1=0, num=0, tmp=0;

int getWordEnd(int x){
	while(++x){
		if(c[x]==' '||c[x]=='\0') break;
	}
	return x;
}

int same(char *x, char *y){
	int len = strlen(x), leny = strlen(y);
	if(len!=leny) return 0;
	for(int i = 0; i < len; ++i){
		if(x[i]!=y[i]) return 0;
	}
	return 1;
}

void numOper(char* word){
//	printf("%s\n", word);
//	int sgn=1, num1=0, num=0, tmp=0;
	
	if(same(word, "negative")) {sgn=-1;}
	else if(same(word, "million")) {num1=(num+tmp)*1000000;num=0;tmp=0;}
	else if(same(word, "thousand")) {num=(num+tmp)*1000;tmp=0;}
	else if(same(word, "hundred")) {num+=tmp*100;tmp=0;}
	
	else if(same(word, "zero")) {tmp=0;}
	else if(same(word, "one")) {tmp=1;}
	else if(same(word, "two")) {tmp=2;}
	else if(same(word, "three")) {tmp=3;}
	else if(same(word, "four")) {tmp=4;}
	else if(same(word, "five")) {tmp=5;}
	else if(same(word, "six")) {tmp=6;}
	else if(same(word, "seven")) {tmp=7;}
	else if(same(word, "eight")) {tmp=8;}
	else if(same(word, "nine")) {tmp=9;}
	
	else if(same(word, "ten")) {num+=10;}
	else if(same(word, "eleven")) {num+=11;}
	else if(same(word, "twelve")) {num+=12;}
	else if(same(word, "thirteen")) {num+=13;}
	else if(same(word, "fourteen")) {num+=14;}
	else if(same(word, "fifteen")) {num+=15;}
	else if(same(word, "sixteen")) {num+=16;}
	else if(same(word, "seventeen")) {num+=17;}
	else if(same(word, "eighteen")) {num+=18;}
	else if(same(word, "nineteen")) {num+=19;}
	else if(same(word, "twenty")) {num+=20;}
	else if(same(word, "thirty")) {num+=30;}
	else if(same(word, "forty")) {num+=40;}
	else if(same(word, "fifty")) {num+=50;}
	else if(same(word, "sixty")) {num+=60;}
	else if(same(word, "seventy")) {num+=70;}
	else if(same(word, "eighty")) {num+=80;}
	else if(same(word, "ninety")) {num+=90;}

//	num+=tmp;tmp=0;
}

void solve(){
	int len = strlen(c);
	sgn=1, num1=0, num=0, tmp=0;
	for(int i = 0; i < len;){
		int end = getWordEnd(i);
//		printf("%.*s\n", end-i, c+i);
		char word[100];
		for(int j = i; j < end; ++j){
			word[j-i]=c[j];
		}word[end-i]='\0';
//		printf("%s\n", word);
		numOper(word);
		i=end+1;
	}
	cout<<sgn*(num1+num+tmp)<<endl;
}

int main(){
	while(1){
		cin.getline(c, 10000, '\n');
		if(c[0]=='\0') break;
		solve();
	}
	return 0;
}

哈夫曼编码树

第一次使用指针构建数据结构,有一个非常大的bug就是priority_queue中的q.top()返回的是一个固定的地址的类,因此不能直接使用,应该new一个之后再使用。还有,尽量少的直接定义用node型变量而是用node* nd = new node来避免重复使用地址。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <typeinfo>

using namespace std;

struct node{
	int val = 0;
	node *fa = nullptr;
	node *son1 = nullptr;
	node *son2 = nullptr;
	bool operator < (const node& tmp) const{
		return val > tmp.val;
	}
};
priority_queue<node> q;

int dfs(node* rt, int d){
	if(rt->son1 == nullptr && rt->son2 == nullptr){
		return (rt->val) * d;
	}
	return dfs(rt->son1, d+1) + 
		   dfs(rt->son2, d+1);
}

void test(){
	int* a, b;
	cout<<typeid(a).name()<<' '<<typeid(b).name()<<endl;
}

node* deepCopy(const node x){
	node* y;
	y->val = x.val;y->son1 = x.son1;y->son2 = x.son2;y->fa = x.fa;
	return y;
}

int main(){
//	test();
	int T;cin>>T;while(T--){
		int n;cin>>n;
		while(!q.empty()) q.pop();
		while(n--){
			int temp;cin>>temp;
			node* tmp = new node;tmp->val = temp;
			q.push(*tmp);
		}
		while(q.size() > 1){
			node* x1 = new node(q.top());q.pop();
			node* x2 = new node(q.top());q.pop();
			node* y = new node;y->val = x1->val + x2->val;
			y->son1 = x1; y->son2 = x2;
			x1->fa = x2->fa = y;
			q.push(*y);
		}
		node* rt = new node(q.top());q.pop();
//		cout<<rt->val<<' '<<rt->son1->val<<' '<<rt->son2->val<<' '<<rt->son1->son1->val<<' '<<rt->son1->son2->val<<endl<<endl;
		cout<<dfs(rt, 0)<<endl;
	}
	return 0;
}

发现它,抓住它

做法1:对森林中每棵并查集建立双向的enemy关系,每次合并相当于是合并最多4棵并查集(即a所在的、a敌对的、b所在的、b敌对的)。每个enemy只存在与树根中,其他节点中的enemy是无效量,从而保证唯一性。注意节点的enemy随时可能失去树根身份,所以使用时必须套上find(en[x])

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int fa[200000], en[200000];

int f(int x){
	if(x == fa[x]) return x;
	return fa[x] = f(fa[x]);
}

int main(){
	int T;cin>>T;
	while(T--){
		int N, M; cin>>N>>M;
		for(int i = 1; i <= N; ++i) {fa[i] = i;en[i] = 0;}
		for(int i = 1; i <= M; ++i){
			char ch;int x, y;cin>>ch>>x>>y;
			x = f(x); y = f(y);
			if(ch == 'A'){
				if(x == y) cout<<"In the same gang."<<endl;
				else if(f(en[x]) == y || f(en[y]) == x) cout<<"In different gangs."<<endl;
				else cout<<"Not sure yet."<<endl;
			}
			else{
				if(f(en[x]) == y && f(en[y]) == x) continue;
				if(f(en[x]) == 0 && f(en[y]) == 0) {en[x] = y; en[y] = x;continue;}
				if(f(en[x])) fa[y] = f(en[x]);
				if(f(en[y])) fa[x] = f(en[y]);
			}
		}
	}
	return 0;
}

做法2:带权并查集,每次路径压缩时更新节点权值。注意路径压缩可以保证m次操作的最坏时间复杂度为\(O(mlogn)\),所以不需要担心额外进行操作会导致复杂度变高。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int fa[200000], en[200000];

int f(int x){
	if(x == fa[x]) return x;
	return fa[x] = f(fa[x]);
}

int main(){
	int T;cin>>T;
	while(T--){
		int N, M; cin>>N>>M;
		for(int i = 1; i <= N; ++i) {fa[i] = i;en[i] = 0;}
		for(int i = 1; i <= M; ++i){
			char ch;int x, y;cin>>ch>>x>>y;
			x = f(x); y = f(y);
			if(ch == 'A'){
				if(x == y) cout<<"In the same gang."<<endl;
				else if(f(en[x]) == y || f(en[y]) == x) cout<<"In different gangs."<<endl;
				else cout<<"Not sure yet."<<endl;
			}
			else{
				if(f(en[x]) == y && f(en[y]) == x) continue;
				if(f(en[x]) == 0 && f(en[y]) == 0) {en[x] = y; en[y] = x;continue;}
				if(f(en[x])) fa[y] = f(en[x]);
				if(f(en[y])) fa[x] = f(en[y]);
			}
		}
	}
	return 0;
}
posted @ 2024-10-24 15:58  hcx1999  阅读(4)  评论(0编辑  收藏  举报