1、统计字符
统计一个给定字符串中指定的字符出现的次数。
测试输入包含若干测试用例,每个测试用例包含2行,第1行为一个长度不超过5的字符串,第2行为一个长度不超过80的字符串。注意这里的字符串包含空格,即空格也可能是要求被统计的字符之一。当读到'#'时输入结束,相应的结果不要输出。
#include<bits/stdc++.h>
using namespace std;
int main()
{
string c;
string n;
while(c[0] != '#'){
getline(cin,c);
getline(cin,n);
int cnt = 0;
int j = 0;
for(int i=0;i<c.length();i++){
for(j=0;j<n.length();j++){
if(c[i]==n[j])
cnt++;
}
if(cnt!=0){
cout << c[i] << " " << cnt << endl;
cnt = 0;
}
}
}
}
2、畅通工程
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M (N, M < =100 );随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
最小生成树问题
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int max_n = 100;
struct node{
int b,e,w;
}edges[max_n];
bool cmp(node n1,node n2){
return n1.w<n2.w;
}
int S[max_n]; // 并查集
int find_root(int x){
while(S[x]>0){
x = S[x];
}
return x;
}
int kruskal()
{
sort(edges,edges+n,cmp);
int sum = 0; // 最小生成树的权值
for(int i = 0;i<n;i++){
// 最小边
node now = edges[i];
// 若不成环可以加入
int fb = find_root(now.b);
int fe = find_root(now.e);
if(fb!=fe){
S[fb]=fe;
sum = sum+now.w;
m--;
}
}
if(m==1)
return sum;
else
return -1;
}
int main(){
while(cin>>n>>m){
if(n==0) break; // 结束条件
memset(S,0,sizeof(S)); // 全初始化为-1或0
for(int i=0;i<n;i++){
cin>>edges[i].b>>edges[i].e>>edges[i].w;
}
int ans = kruskal();
if(ans==-1){
cout<<"?"<<endl;
}else cout << ans <<endl;
}
}
3、畅通工程2
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 注意:两个城市之间可以有多条道路相通,也就是说 3 3 1 2 1 2 2 1 这种输入也是合法的 当N为0时,输入结束,该用例不被处理。
并查集的应用
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int max_n = 1000;
int S[max_n];
int find_root(int x){
while(S[x]>0){
x = S[x];
}
return x;
}
int main(){
while(cin>>n>>m) {
if (n == 0) break;
memset(S, 0, sizeof S);
int sum = 0;
for(int i =0;i<m;i++){
int x,y;
cin >> x >> y;
int fx = find_root(x);
int fy = find_root(y);
if(fx!=fy){
S[fx] = fy;
sum++;
}
}
cout << n-sum-1 << endl;
}
}
4.继续畅通工程
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。 当N为0时输入结束。
#include<bits/stdc++.h>
using namespace std;
const int max_n=100;
int n;
struct node{
int u,v,w;
int flag;
}edges[max_n];
int cmp(node n1, node n2){
return n1.w < n2.w;
}
int S[max_n];
int find_root(int x){
while(S[x]>0){
x = S[x];
}
return x;
}
int kruskal(int m){
sort(edges,edges+m,cmp);
int sum = 0;
int total = 0;
for(int i=0;i<m;i++){
node now = edges[i];
int fa = find_root(now.u);
int fb = find_root(now.v);
if(total == n-1){
break;
}
if(fa!=fb){
sum = sum + now.w;
S[fa] = fb;
total++;
}
}
return sum;
}
int main(){
while(cin>>n){
if(n==0) break;
memset(S,-1,sizeof(S));
int m = n*(n-1)/2;
for(int i=0;i<m;i++){
cin>>edges[i].u>>edges[i].v>>edges[i].w>>edges[i].flag;
if(edges[i].flag==1) edges[i].w=0;
}
int ret = kruskal(m);
cout << ret << endl;
}
}
5.二叉搜索树
判断两序列是否为同一二叉搜索树序列
开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束。 接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树。 接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树。
#include<bits/stdc++.h>
using namespace std;
typedef struct node{
char data; // 注意是以字符形式建树
struct node *lchild,*rchild;
}*BitTree;
vector<char> right_ans,each_ans;
void InsertBitTree(BitTree &T,char x){
if(T==NULL){
T = new node;
T->data = x;
T->lchild = NULL;
T->rchild = NULL;
return; // 递归终止
}else if(T->data > x){
InsertBitTree(T->lchild,x);
}else if(T->data < x){
InsertBitTree(T->rchild,x);
}
}
void PreOrderTraverse(BitTree T) {
if (T == NULL) return;
each_ans.push_back(T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
int main(){
int n;
string right,each;
while(cin>>n){
if(n==0) return 0;
cin >> right;
BitTree T = NULL;
for(int i = 0;i<right.size();i++){
InsertBitTree(T,right[i]);
}
PreOrderTraverse(T);
for (int i = 0; i < each_ans.size(); ++i) right_ans.push_back(each_ans[i]); // 函数里默认写的是each_ans
while(n--){
each_ans = {};
cin>>each;
BitTree T = NULL;
for(int i = 0;i<each.size();i++){
InsertBitTree(T,each[i]);
}
PreOrderTraverse(T);
int flag = 1;
for(int i=0;i<each.size();i++){
if(right_ans[i]!=each_ans[i]){
flag = 0;
break;
}
}
if(flag==1){
cout << "YES" << endl;
}else{
cout << "NO" << endl;
}
}
}
}
6.统计同成绩学生人数
读入N名学生的成绩,将获得某一给定分数的学生人数输出。
测试输入包含若干测试用例,每个测试用例的格式为 第1行:N 第2行:N名学生的成绩,相邻两数字用一个空格间隔。 第3行:给定分数 当读到N=0时输入结束。其中N不超过1000,成绩分数为(包含)0到100之间的一个整数。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
if(n==0) return 0;
map<int,int> a;
int grade,aim;
while(n--){
cin>>grade;
a[grade]++;
}
cin>>aim;
cout << a[aim] << endl;
}
}
7.EXCEL排序
Excel可以对一组纪录按任意指定列排序。现请你编写程序实现类似功能。 对每个测试用例,首先输出1行“Case i:”,其中 i 是测试用例的编号(从1开始)。随后在 N 行中输出按要求排序后的结果,即:当 C=1 时,按学号递增排序;当 C=2时,按姓名的非递减字典序排序;当 C=3 时,按成绩的非递减排序。当若干学生具有相同姓名或者相同成绩时,则按他们的学号递增排序。
测试输入包含若干测试用例。每个测试用例的第1行包含两个整数 N (N<=100000) 和 C,其中 N 是纪录的条数,C 是指定排序的列号。以下有N行,每行包含一条学生纪录。每条学生纪录由学号(6位数字,同组测试中没有重复的学号)、姓名(不超过8位且不包含空格的字符串)、成绩(闭区间[0, 100]内的整数)组成,每个项目间用1个空格隔开。当读到 N=0 时,全部输入结束,相应的结果不要输出。
#include<bits/stdc++.h>
using namespace std;
const int max_N = 100000;
struct student{
string No;
string name;
int grade;
}students[max_N];
bool cmp1(struct student stu1,struct student stu2){
return stu1.No < stu2.No;
}
bool cmp2(struct student stu1,struct student stu2){
if(stu1.name == stu2.name){
return stu1.No < stu2.No;
}else{
return stu1.name < stu2.name;
}
}
bool cmp3(struct student stu1,struct student stu2){
if(stu1.grade == stu2.grade){
return stu1.No < stu2.No;
}else{
return stu1.grade < stu2.grade;
}
}
int main(){
int N,C;
cin >> N >> C;
for(int i=0;i<N;i++){
struct student stu;
cin >> stu.No >> stu.name >> stu.grade;
students[i] = stu;
}
if(C==1){
sort(students,students+N,cmp1);
}else if(C==2){
sort(students,students+N,cmp2);
}else if(C==3){
sort(students,students+N,cmp3);
}
cout << "Case:"<<endl;
for(int i=0;i<N;i++){
cout << students[i].No << " "<<students[i].name<<" " << students[i].grade<<endl;
}
}
8.最大连续子序列
给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。现在增加一个要求,即还需要输出该子序列的第一个和最后一个元素。
测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K< 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。
#include<bits/stdc++.h>
using namespace std;
const int max_k = 10000;
int dp[max_k],dp_copy[max_k];
int main(){
int k;
while(cin>>k){
int flag = 0; // 是否全为负数
if(k==0) return 0;
memset(dp,0,max_k);
for(int i = 0;i<k;i++){
cin>>dp[i];
if(dp[i]>=0){
flag = 1;
}
dp_copy[i] = dp[i];
}
if(flag){
for(int i = 1;i<k;i++){
dp[i] = max(dp[i-1]+dp[i],dp[i]);
}
int max_value =*max_element(dp,dp+k);
int max_pos = distance(dp,max_element(dp,dp+k));
int temp = max_value;
int min_pos = max_pos;
while(dp_copy[min_pos]!=temp){
temp = temp - dp_copy[min_pos];
min_pos--;
}
cout << max_value <<" "<<dp_copy[min_pos]<<" "<<dp_copy[max_pos]<<endl;
}else{
cout << 0 <<" "<<dp_copy[0]<<" "<<dp_copy[k-1]<<endl;
}
}
}
9.最短路径问题
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。 (1<n<=1000, 0<m<100000, s != t)
有n个集合(初始有n个点,一个点独自成一个集合),先选出一条最短的边,假设它属于集合u,然后从跟它邻接的边中选出一条最短的且不与集合u中已经存在的边形成回路的边,合并到集合u中,再从非u集合中选出一条与集合u中的边邻接且距离最短的边,加入到集合u中,以此类推。
Dijkstra是用来解决给定起点和重点求路径的问题。
#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 1000;
int visited[MAX_N]; // 是否已经访问过该点
int dist[MAX_N]; // dist[i]起点到i的距离
int cost[MAX_N]; // cost[i]起点到i的花费
struct Edge{
int to;
int length;
int price;
Edge(int i, int j, int k): to(i), length(j), price(k){}
};
vector<Edge> graph[MAX_N];
struct Point{
int number;
int distance;
Point(int i, int j): number(i), distance(j){}
bool operator< (const Point& p) const{ // 重定义操作符< 使得Point之间可比
return distance > p.distance;
}
};
void Dijkstra(int s, int n){ // s到n的最短路
dist[s] = 0;
cost[s] = 0;
priority_queue<Point> q; // 优先队列
q.push(Point(s, 0)); // 加入起点 起点到起点距离显然为0
while(!q.empty()){ // 只要q不空
int u = q.top().number; // 队列头
q.pop();
if(visited[u] == 1){ // 已经被访问过
continue;
}
visited[u] = 1; // 未被访问过 则标记位访问过
for(int i=0; i<graph[u].size(); i++){ // 遍历与u邻接的边
int v = graph[u][i].to;
int uv_price = graph[u][i].price;
int uv_len = graph[u][i].length;
if(dist[u] + uv_len < dist[v] || (dist[u] + uv_len == dist[v] && cost[u] + uv_price < cost[v])){ // 直达距离更短或距离相同但花费更少
// 更新从起点到v的距离
dist[v] = dist[u] + uv_len;
cost[v] = cost[u] + uv_price;
}
q.push(Point(v, dist[v])); // 加入v 下次循环找v的邻接...
}
}
}
int main(){
int m, n;
while(cin>>n>>m){
if(n == 0 && m==0) break;
memset(graph, 0, sizeof(graph));
memset(cost, 0x3f, sizeof(cost)); // 0x3f表示无限大
memset(dist, 0x3f, sizeof(dist)); // 0x3f表示无限大
memset(visited, 0, sizeof(visited)); // 都是未访问
for(int i=0; i<m; i++){
int from, to, d, c;
cin>>from>>to>>d>>c;
graph[from].push_back(Edge(to, d, c));
graph[to].push_back(Edge(from, d, c));
}
int s, t;
cin>>s>>t;
Dijkstra(s, n);
cout<<dist[t]<<" "<<cost[t]<<endl;
}
return 0;
}
10.xxx定律
对于一个数n,如果是偶数,就把n砍掉一半;如果是奇数,把n变成 3*n+ 1后砍掉一半,直到该数变为1为止。 请计算需要经过几步才能将n变到1,具体可见样例。
测试包含多个用例,每个用例包含一个整数n,当n为0 时表示输入结束。(1<=n<=10000)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
if(n==0) return 0;
int cnt = 0;
while(n!=1){
if(n%2==0){
n = n/2;
}else{
n = (3*n+1)/2;
}
cnt++;
}
cout << cnt << endl;
}
}