16.公路村村通
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int n,m,tu[1005][1005],ut[505][505],visit[505],dist[505],price[1005];
int main()
{
int a,b,c,e,n,m,s,d;
int i,j,k=0;
cin>>n>>m;
memset(tu,MAX_MM,sizeof tu);
for(i=0; i<m; i++)
{
cin>>a>>b>>c;
tu[a][b]=tu[b][a]=c;
}
price[1]=0;
for(i=2; i<=n; i++)
{
price[i]=tu[1][i];
}
int sum=0;
for(i=2; i<=n; i++)
{
int minn=MAX_MM;
k=0;
for(j=1; j<=n; j++)
{
if(price[j]!=0&&price[j]<minn)
{
minn=price[j];
k=j;
}
}
if(k==0)
{
cout<<-1;
return 0;
}
sum+=minn;
price[k]=0;
for(j=1; j<=n; j++)
{
if(tu[k][j]<price[j])
{
price[j]=tu[k][j];
}
}
}
cout<<sum;
return 0;
}
17.任务调度的合理性
假定一个工程项目由一组子任务构成,子任务之间有的可以并行执行,有的必须在完成了其它一些子任务后才能执行。“任务调度”包括一组子任务、以及每个子任务可以执行所依赖的子任务集。
比如完成一个专业的所有课程学习和毕业设计可以看成一个本科生要完成的一项工程,各门课程可以看成是子任务。有些课程可以同时开设,比如英语和C程序设计,它们没有必须先修哪门的约束;有些课程则不可以同时开设,因为它们有先后的依赖关系,比如C程序设计和数据结构两门课,必须先学习前者。
但是需要注意的是,对一组子任务,并不是任意的任务调度都是一个可行的方案。比如方案中存在“子任务A依赖于子任务B,子任务B依赖于子任务C,子任务C又依赖于子任务A”,那么这三个任务哪个都不能先执行,这就是一个不可行的方案。你现在的工作是写程序判定任何一个给定的任务调度是否可行。
输入格式:
输入说明:输入第一行给出子任务数N(≤100),子任务按1~N编号。随后N行,每行给出一个子任务的依赖集合:首先给出依赖集合中的子任务数K,随后给出K个子任务编号,整数之间都用空格分隔。
输出格式:
如果方案可行,则输出1,否则输出0。
输入样例1:
12
0
0
2 1 2
0
1 4
1 5
2 3 6
1 3
2 7 8
1 7
1 10
1 7
输出样例1:
1
输入样例2:
5
1 4
2 1 4
2 2 5
1 3
0
输出样例2:
0
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int n,q[105],rudu[105],tu[105][105],rukai,qkai,qshi,num;
int main()
{
int a,b,c,e,m,s,d;
int i,j,k=0;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a;
for(j=0;j<a;j++)
{
cin>>b;
tu[b][i]=1;
rudu[i]++;
}
if(rudu[i]==0)q[qkai++]=i;
}
while(qshi<qkai)
{
c=q[qshi++];
for(i=1;i<=n;i++)
{
if(tu[c][i]&&--rudu[i]==0)
{
q[qkai++]=i;
}
}
}
if(qkai==n)cout<<1;
else
cout<<0;
return 0;
}
18.家庭房产
给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。
输入格式:
输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产:
编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积
其中编号
是每个人独有的一个4位数的编号;父
和母
分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1
);k
(0≤k
≤5)是该人的子女的个数;孩子i
是其子女的编号。
输出格式:
首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:
家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积
其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。
输入样例:
10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100
输出样例:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
#include <bits/stdc++.h>
using namespace std;
#define MAX_MM 999999
int pre[10005],cy[10005],vis[10005];
struct nide
{
int id,fa,ma,chd;
int hnum,harea,ch[6];
}faml[10005];
struct node
{
int id,num;
double anum,aarea;
}ffml[10005];
int finde(int x)
{
if(pre[x]==x)return x;
else
return pre[x]=finde(pre[x]);
}
void cpp(int x,int y)
{
x=finde(x);
y=finde(y);
if(x>y)pre[x]=y;
else
pre[y]=x;
}
bool cmp(node x,node y)
{
if(x.aarea!=y.aarea)return x.aarea>y.aarea;
else
return x.id<y.id;
}
int main()
{
int i,j,n,x,y,z,k,s,d,t;
cin>>n;
for(i=0;i<=10005;i++)
{
pre[i]=i;
}
for(i=0;i<n;i++)
{
cin>>faml[i].id>>faml[i].fa>>faml[i].ma>>faml[i].chd;
cy[faml[i].id]=1;
if(faml[i].fa!=-1)
{
cpp(faml[i].id,faml[i].fa);
cy[faml[i].fa]=1;
}
if(faml[i].ma!=-1)
{
cpp(faml[i].id,faml[i].ma);
cy[faml[i].ma]=1;
}
for(j=0;j<faml[i].chd;j++)
{
cin>>faml[i].ch[j];
if(faml[i].ch[j]!=-1)
{
cpp(faml[i].id,faml[i].ch[j]);
cy[faml[i].ch[j]]=1;
}
}
cin>>faml[i].hnum>>faml[i].harea;
}
for(i=0;i<10005;i++)
{
ffml[i].id=-1;
}
int jia=0;
for(i=0;i<n;i++)
{
t=finde(faml[i].id);
if(vis[t]==0)
{
jia++;
}
vis[t]=1;
ffml[t].id=t;
ffml[t].aarea+=faml[i].harea;
ffml[t].anum+=faml[i].hnum;
}
for(i=0;i<10005;i++)
{
if(cy[i]==1)ffml[finde(i)].num++;
}
for(i=0;i<10005;i++)
{
if(ffml[i].id!=-1)
{
ffml[i].aarea=ffml[i].aarea*1.0/ffml[i].num;
ffml[i].anum=ffml[i].anum*1.0/ffml[i].num;
}
}
sort(ffml,ffml+10005,cmp);
cout<<jia<<endl;
for(i=0;i<jia;i++)
{
printf("%04d %d %.3lf %.3lf\n",ffml[i].id,ffml[i].num,ffml[i].anum,ffml[i].aarea);
}
return 0;
}
19.最短工期
一个项目由若干个任务组成,任务之间有先后依赖顺序。项目经理需要设置一系列里程碑,在每个里程碑节点处检查任务的完成情况,并启动后续的任务。现给定一个项目中各个任务之间的关系,请你计算出这个项目的最早完工时间。
输入格式:
首先第一行给出两个正整数:项目里程碑的数量 N(≤100)和任务总数 M。这里的里程碑从 0 到 N−1 编号。随后 M 行,每行给出一项任务的描述,格式为“任务起始里程碑 任务结束里程碑 工作时长”,三个数字均为非负整数,以空格分隔。
输出格式:
如果整个项目的安排是合理可行的,在一行中输出最早完工时间;否则输出"Impossible"。
输入样例 1:
9 12
0 1 6
0 2 4
0 3 5
1 4 1
2 4 1
3 5 2
5 4 0
4 6 9
4 7 7
5 7 4
6 8 2
7 8 4
输出样例 1:
18
输入样例 2:
4 5
0 1 1
0 2 2
2 1 3
1 3 4
3 2 5
输出样例 2:
Impossible
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int tu[105][105],ru[105],t[105];
int q[105],qshi=0,qend=0;
int sum=0;
int main()
{
int a,b,c,e,n,m,s,d;
int i,j,k=0;
cin>>n>>m;
for(i=0; i<m; i++)
{
cin>>a>>b>>c;
tu[a][b]=c;
ru[b]++;
}
for(i=0; i<n; i++)
{
if(!ru[i])
{
q[qend++]=i;
}
}
while(qshi<qend)
{
s=q[qshi++];
for(i=0; i<n; i++)
{
if(tu[s][i]!=0)
{
t[i]=max(t[i],t[s]+tu[s][i]);
if(--ru[i]==0)
{
q[qend++]=i;
}
}
}
}
if(qend>=n)
{
for(i=0; i<n; i++)
{
if(t[i]>t[sum])
{
sum=i;
}
}
cout<<t[sum];
}
else
cout<<"Impossible";
return 0;
}
20.路径判断
给定一个有N个顶点和E条边的无向图,请判断给定的两个顶点之间是否有路径存在。
假设顶点从0到N−1编号。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。
随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
最后一行给出两个顶点编号i,j(0≤i,j<N),i和j之间用空格分隔。
输出格式:
如果i和j之间存在路径,则输出"There is a path between i and j.",
否则输出"There is no path between i and j."。
输入样例1:
7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 3
输出样例1:
There is a path between 0 and 3.
输入样例2:
7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 6
输出样例2:
There is no path between 0 and 6.
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int tu[105][105],ru[105],vis[105],dis[105][105];
int q[105],qshi=0,qend=0;
int sum=0;
int main()
{
int a,b,c,e,n,m,s,d;
int i,j,k=0;
cin>>n>>e;
memset(tu,MAX_MM,sizeof tu);
for(i=0;i<e;i++)
{
cin>>a>>b;
tu[a][b]=tu[b][a]=1;
}
for(i=0;i<15;i++)
{
tu[i][i]=1;
}
for(k=0;k<n;k++)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(tu[i][k]==1&&tu[k][j]==1)
{
tu[i][j]=1;
}
}
}
}
cin>>c>>d;
if(tu[c][d]==1)cout<<"There is a path between "<<c<<" and "<<d<<".";
else
{
cout<<"There is no path between "<<c<<" and "<<d<<".";
}
return 0;
}
21.最短路径
给定一个有N个顶点和E条边的无向图,顶点从0到N−1编号。请判断给定的两个顶点之间是否有路径存在。如果存在,给出最短路径长度。
这里定义顶点到自身的最短路径长度为0。
进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。
随后E行,每行给出一条边的两个顶点。每行中的数字之间用1空格分隔。
最后一行给出两个顶点编号i,j(0≤i,j<N),i和j之间用空格分隔。
输出格式:
如果i和j之间存在路径,则输出"The length of the shortest path between i and j is X.",X为最短路径长度,
否则输出"There is no path between i and j."。
输入样例1:
7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 3
输出样例1:
The length of the shortest path between 0 and 3 is 2.
输入样例2:
7 6
0 1
2 3
1 4
0 2
1 3
5 6
0 6
输出样例2:
There is no path between 0 and 6.
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int tu[105][105],vis[105][105];
int main()
{
int a,b,c,e,n,m,s,d;
int i,j,k=0;
cin>>n>>e;
memset(vis,MAX_MM,sizeof vis);
for(i=0;i<e;i++)
{
cin>>a>>b;
tu[a][b]=tu[b][a]=1;
vis[a][b]=vis[b][a]=1;
}
for(i=0;i<10;i++)
{
tu[i][i]=1;
vis[i][i]=0;
}
for(k=0;k<n;k++)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(tu[i][k]==1&&tu[k][j]==1) {
vis[i][j]=min(vis[i][j],vis[i][k]+vis[k][j]);
tu[i][j]=1;
}
}
}
}
cin>>c>>d;
if(tu[c][d]==1)cout<<"The length of the shortest path between "<<c<<" and "<<d<<" is "<<vis[c][d]<<".";
else
{
cout<<"There is no path between "<<c<<" and "<<d<<".";
}
return 0;
}
22.Dijkstra算法(基础)
给一个n(1 ≤ n ≤ 2500) 个点 m(1 ≤ m ≤ 6200) 条边的无向图,求 s 到 t 的最短路。
输入格式:
第一行四个由空格隔开的整数 n、m、s、t。
之后的 m 行,每行三个正整数 si、ti、wi(1≤wi≤109),表示一条从si 到 ti 长度为 wi 的边。
输出格式:
一个整数,表示从s 到t 的最短路径长度。数据保证至少存在一条道路。
输入样例:
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
输出样例:
7
#include <bits/stdc++.h>
#define MAX_MM 9999999
using namespace std;
int tu[2505][2505],dis[2505],vis[2505];
int main()
{
int a,b,c,e,n,m,s,d,t;
int i,j,k=0;
memset(tu,MAX_MM,sizeof tu);
memset(dis,MAX_MM,sizeof dis);
cin>>n>>m>>s>>t;
for(i=0;i<m;i++)
{
scanf("%d %d %d",&a,&b,&c);
tu[a][b]=tu[b][a]=c;
}
vis[s]=1;
dis[s]=0;
for(i=1;i<=n;i++)
{
k=s;
int minn=MAX_MM;
for(j=1;j<=n;j++)
{
if(vis[j]==0&&minn>dis[j])
{
minn=dis[j];
k=j;
}
}
vis[k]=1;
for(j=1;j<=n;j++)
{
dis[j]=min(dis[j],dis[k]+tu[k][j]);
}
}
cout<<dis[t];
return 0;
}
22.单身狗
“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。
输入格式:
输入第一行给出一个正整数 N(≤50000),是已知夫妻/伴侣的对数;随后 N 行,每行给出一对夫妻/伴侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤10000),为参加派对的总人数;随后一行给出这 M 位客人的 ID,以空格分隔。题目保证无人重婚或脚踩两条船。
输出格式:
首先第一行输出落单客人的总人数;随后第二行按 ID 递增顺序列出落单的客人。ID 间用 1 个空格分隔,行的首尾不得有多余空格。
输入样例:
3
11111 22222
33333 44444
55555 66666
7
55555 44444 10000 88888 22222 11111 23333
输出样例:
5
10000 23333 44444 55555 88888
#include <bits/stdc++.h>
using namespace std;
map<int,int> tu;
vector<int> tt;
set<int> ji;
set<int> yuan;
int cmp(int x,int y)
{
return x<y;
}
int main()
{
int n,m,a,b,c,i,j,k;
cin>>n;
int s,t;
for(i=0;i<n;i++)
{
cin>>s>>t;
yuan.insert(s);
yuan.insert(t);
tu[s]=t;
tu[t]=s;
}
cin>>m;
for(i=0;i<m;i++)
{
cin>>s;
ji.insert(s);
}
for(set<int>::iterator it=ji.begin();it!=ji.end();it++)
{
if(!(yuan.count(*it)&&ji.count(tu[*it])))
{
tt.push_back(*it);
}
}
sort(tt.begin(),tt.end(),cmp);
cout<<tt.size()<<endl;
for(i=0;i<tt.size();i++)
{
if(i==0)printf("%05d",tt[i]);
else
printf(" %05d",tt[i]);
}
return 0;
}
23.中序遍历树并判断是否为二叉搜索树
对给定的有N
个节点(N>=0
)的二叉树,给出中序遍历序列,并判断是否为二叉搜索树。
题目保证二叉树不超过200
个节点,节点数值在整型int
范围内且各不相同。
输入格式:
第一行是一个非负整数N
,表示有N
个节点
第二行是一个整数k
,是树根的元素值
接下来有N-1
行,每行是一个新节点,格式为 r d e
三个整数,
r
表示该节点的父节点元素值(保证父节点存在);d
是方向,0
表示该节点为父节点的左儿子,1
表示右儿子;e
是该节点的元素值
输出格式:
首先输出二叉树的中序遍历序列,每个元素占一行。对于空树,不输出任何内容。
然后如果给定的树是二叉搜索树,输出Yes
否则输出No
输入样例:
对于图片中的二叉树:
3
20
20 0 10
20 1 25
输出样例:
10
20
25
Yes
#include <bits/stdc++.h>
using namespace std;
vector<int> res, tmp;
int n;
struct tree{
int val;
tree* left;
tree* right;
};
void inorder(tree* root){
if(!root) return;
inorder(root->left);
cout<<root->val<<endl;
res.push_back(root->val);
inorder(root->right);
}
int main(){
map<int, tree*> mp;
cin>>n;
int x, d, e;
tree* root = NULL;
for(int i = 1; i <= n; i ++){
cin>>x;
if(i != 1){
cin>>d>>e;
tree* r = mp[x];
tmp.push_back(e);
if(d == 0) {
r->left = (struct tree *)malloc(sizeof(struct tree));
r->left->val=e;
r->left->left=NULL;
r->left->right=NULL;
mp[e] = r->left;
}else{
r->right= (struct tree *)malloc(sizeof(struct tree));
r->right->val=e;
r->right->right=NULL;
r->right->left=NULL;
mp[e] = r->right;
}
}else{
root = (struct tree *)malloc(sizeof(struct tree));
root->val=x;
root->left=NULL;
root->right=NULL;
mp[x] = root;
tmp.push_back(x);
}
}
inorder(root);
sort(tmp.begin(), tmp.end());
if(res == tmp) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
24.词频统计
请编写程序,对一段英文文本,统计其中所有不同单词的个数,以及词频最大的前10%的单词。
所谓“单词”,是指由不超过80个单词字符组成的连续字符串,但长度超过15的单词将只截取保留前15个单词字符。而合法的“单词字符”为大小写字母、数字和下划线,其它字符均认为是单词分隔符。
输入格式:
输入给出一段非空文本,最后以符号#
结尾。输入保证存在至少10个不同的单词。
输出格式:
在第一行中输出文本中所有不同单词的个数。注意“单词”不区分英文大小写,例如“PAT”和“pat”被认为是同一个单词。
随后按照词频递减的顺序,按照词频:单词
的格式输出词频最大的前10%的单词。若有并列,则按递增字典序输出。
输入样例:
This is a test.
The word "this" is the word with the highest frequency.
Longlonglonglongword should be cut off, so is considered as the same as longlonglonglonee. But this_8 is different than this, and this, and this...#
this line should be ignored.
输出样例:(注意:虽然单词the
也出现了4次,但因为我们只要输出前10%(即23个单词中的前2个)单词,而按照字母序,the
排第3位,所以不输出。)
23
5:this
4:is
#include <bits/stdc++.h>
using namespace std;
map<string,int> tu;
bool cmp(pair<string,int> x,pair<string,int> y)
{
if(x.second!=y.second)return x.second>y.second;
else
return x.first<y.first;
}
int main()
{
int n,m,a,b,c,i,j,k;
char ch;
string s;
while(~scanf("%c",&ch))
{
if(ch!='#')
{
if(ch>='0'&&ch<='9'||ch=='_'||ch>='a'&&ch<='z')
{
if(s.size()<15)
s+=ch;
}
else if(ch>='A'&&ch<='Z')
{
if(s.size()<15)
{
ch+=32;
s+=ch;
}
}
else
{
if(s.size()!=0)
{
tu[s]++;
s="";
}
}
}
else if(ch=='#')break;
}
vector<pair<string,int>> st;
for(map<string,int>::iterator it=tu.begin(); it!=tu.end(); it++)
{
st.push_back(make_pair(it->first,it->second));
}
sort(st.begin(),st.end(),cmp);
m=st.size()/10;
cout<<st.size()<<endl;
for(int i=0;i<m;i++)
{
cout<<st[i].second<<":"<<st[i].first<<endl;
}
return 0;
}
24.悄悄关注
新浪微博上有个“悄悄关注”,一个用户悄悄关注的人,不出现在这个用户的关注列表上,但系统会推送其悄悄关注的人发表的微博给该用户。现在我们来做一回网络侦探,根据某人的关注列表和其对其他用户的点赞情况,扒出有可能被其悄悄关注的人。
输入格式:
输入首先在第一行给出某用户的关注列表,格式如下:
人数N 用户1 用户2 …… 用户N
其中N
是不超过5000的正整数,每个用户i
(i
=1, ..., N
)是被其关注的用户的ID,是长度为4位的由数字和英文字母组成的字符串,各项间以空格分隔。
之后给出该用户点赞的信息:首先给出一个不超过10000的正整数M
,随后M
行,每行给出一个被其点赞的用户ID和对该用户的点赞次数(不超过1000),以空格分隔。注意:用户ID是一个用户的唯一身份标识。题目保证在关注列表中没有重复用户,在点赞信息中也没有重复用户。
输出格式:
我们认为被该用户点赞次数大于其点赞平均数、且不在其关注列表上的人,很可能是其悄悄关注的人。根据这个假设,请你按用户ID字母序的升序输出可能是其悄悄关注的人,每行1个ID。如果其实并没有这样的人,则输出“Bing Mei You”。
输入样例1:
10 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao
8
Magi 50
Pota 30
LLao 3
Ammy 48
Dave 15
GAO3 31
Zoro 1
Cath 60
输出样例1:
Ammy
Cath
Pota
输入样例2:
11 GAO3 Magi Zha1 Sen1 Quan FaMK LSum Eins FatM LLao Pota
7
Magi 50
Pota 30
LLao 48
Ammy 3
Dave 15
GAO3 31
Zoro 29
输出样例2:
Bing Mei You
#include <bits/stdc++.h>
using namespace std;
map<string,int> tu;
map<string,int> ut;
int main()
{
int n,m,a,b,c,i,j,k;
cin>>n;
string s;
char ch;
for(i=0;i<n;i++)
{
cin>>s;
ut[s]=1;
}
cin>>m;
int sum=0;
for(i=0;i<m;i++)
{
cin>>s>>a;
tu[s]=a;
sum+=a;
}
double num=sum*1.0/m;
int flag=0;
for(map<string,int>::iterator it=tu.begin();it!=tu.end();it++)
{
if(ut[it->first]!=1&&it->second*1.0>num)
{cout<<it->first<<endl;flag=1;}
}
if(flag==0)cout<<"Bing Mei You";
return 0;
}
25.寻找第k小的数
给定若干整数,请设计一个高效的算法,确定第k小的数。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据的第1行输入2个整数n,k(1≤k≤n≤1000000)。第2行输入n个整数,每个数据的取值范围在0到1000000之间。
输出格式:
对于每组测试,输出第k小的数。
输入样例:
5 3
1 2 2 2 1
9 3
1 2 3 4 5 6 9 8 7
输出样例:
2
3
提示:
如果提交后超时,请注意需要设计的是高效的算法!如果你初学《数据结构》,暂时设计不出来,请学完相关知识再回头来做。
也可以使用STL之sort、nth_element函数求解。
另外,由于输入数据特别多,为减少输入数据的耗时,建议使用以下的输入外挂函数:
void scan_d(int &num)
{
char in;
in=getchar();
while(in<'0'||in>'9') in=getchar();
num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}
}
调用方法如下:
int n;
scan_d(n);
#include <stdio.h>
#include <stdlib.h>
int zu[1000001],countt,num;
void scan_d()
{
char in;
in=getchar();
while(in<'0'||in>'9') in=getchar();
num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}
}
void kuaipai(int x,int y)
{
if(x>=y)return;
int i=x,j=y;
int mid=zu[x];
while(i<j)
{
while(i<j&&zu[j]>mid)
j--;
zu[i]=zu[j];
while(i<j&&zu[i]<=mid)
i++;
zu[j]=zu[i];
}
zu[i]=mid;
kuaipai(x,i-1);
kuaipai(i+1,y);
}
int main()
{
int i,j,k,n;
while(~scanf("%d %d",&n,&k))
{
for(i=0; i<n; i++)
{
scan_d();
zu[i]=num;
}
kuaipai(0,n-1);
printf("%d\n",zu[k-1]);
}
return 0;
}
26.逆序对
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。
输入格式:
第一行包含整数n,表示数列的长度;第二行包含 n 个整数,表示整个数列。(1≤n≤100000)
输出格式:
输出一个整数,表示逆序对的个数。
输入样例:
6
2 3 4 5 6 1
输出样例:
5
#include <bits/stdc++.h>
using namespace std;
int a[100001],b[100001];
long long finde(int l,int r)
{
if(l>=r) return 0;
int mid=(l+r)/2;
long long res=finde(l,mid)+finde(mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
if(a[i]<=a[j]) b[k++]=a[i++];
else
{
res+=mid+1-i;
b[k++]=a[j++];
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(int i=l,j=0;i<=r;i++,j++) a[i]=b[j];
return res;
}
int main()
{
int n,i,m,c,j,k,t;
cin>>n;
for(i=0; i<n; i++)
{
cin>>a[i];
}
long long sum=finde(0,n-1);
cout<<sum;
return 0;
}
27.插入排序还是归并排序
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式:
首先在第 1 行中输出Insertion Sort
表示插入排序、或Merge Sort
表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
输出样例 2:
Merge Sort
1 2 3 8 4 5 7 9 0 6
#include <bits/stdc++.h>
using namespace std;
int a[101],b[101];
bool tong(int n)
{
int i;
for(i=0; i<n; i++)
{
if(a[i]!=b[i])return false;
}
return true;
}
int main()
{
int n,i,m,c,j,k,t;
cin>>n;
for(i=0; i<n; i++)
{
cin>>a[i];
}
for(i=0; i<n; i++)
{
cin>>b[i];
}
for(i=1; i<n; i++)
{
if(b[i-1]>b[i])break;
}
int flag=0;
for(j=i; j<n; j++)
{
if(b[j]!=a[j])
{
flag=1;
break;
}
}
if(flag==0)
{
cout<<"Insertion Sort"<<endl;
sort(b,b+i+1);
for(i=0; i<n; i++)
{
if(i==0)cout<<b[i];
else
cout<<" "<<b[i];
}
}
else
{
cout<<"Merge Sort"<<endl;
for(i=2; !tong(n); i+=i)
{
for(j=0; j<n; j+=i)
{
sort(a+j,a+min(j+i,n));
}
}
for(j=0; j<n; j+=i)
{
sort(a+j,a+min(j+i,n));
}
for(i=0; i<n; i++)
{
if(i==0)cout<<a[i];
else
cout<<" "<<a[i];
}
}
return 0;
}
28.堆排序
给定一个整数序列,请按非递减序输出采用堆排序的各趟排序后的结果。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。
输出格式:
对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。
输入样例:
4
8 7 2 1
输出样例:
7 1 2 8
2 1 7 8
1 2 7 8
#include <bits/stdc++.h>
using namespace std;
void zuida(int a[],int n,int k)
{
int root=k;
int le=k*2;
int ri=k*2+1;
if(le<=n&&a[le-1]>a[root-1])
{
root=le;
}
if(ri<=n&&a[ri-1]>a[root-1])
{
root=ri;
}
if(root!=k)
{
int t=a[root-1];
a[root-1]=a[k-1];
a[k-1]=t;
zuida(a,n,root);
}
}
void dui(int a[],int n)
{
int i,j,k,x;
for(i=n/2;i>=1;i--)
{
zuida(a,n,i);
}
k=n;
for(i=n;i>1;i--)
{
j=a[0];
a[0]=a[i-1];
a[i-1]=j;
k--;
zuida(a,k,1);
for(x=0;x<n;x++)
{
if(x==0)cout<<a[x];
else
cout<<" "<<a[x];
}
cout<<endl;
}
}
int main()
{
int n,i,m,c,j,k,t,a[101];
while(~scanf("%d",&n))
{
for(i=0; i<n; i++)
{
cin>>a[i];
}
dui(a,n);
}
return 0;
}
29.寻找大富翁
胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。
输入格式:
输入首先给出两个正整数N(≤106)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。
输出格式:
在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。
输入样例:
8 3
8 12 7 3 20 9 5 18
输出样例:
20 18 12
#include <bits/stdc++.h>
using namespace std;
long int gling[1000001];
int main()
{
long int n,a,i,m,b,c,j,k;
cin>>n>>m;
for(i=0; i<n; i++)
{
cin>>a;
gling[i]=a;
}
sort(gling,gling+n);
if(n<m)
m=n;
for(i=n-1; i>=0; i--)
{
if(m==0)break;
else
{
if(i==n-1)cout<<gling[i];
else
cout<<" "<<gling[i];
m--;
}
}
return 0;
}
30.归并排序
知识点:归并排序
给定你一个长度为 n 的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式:
输入共两行,第一行包含整数 n(1≤n≤100000)。
第二行包含 n 个整数(所有整数均在 1∼10^9 范围内),表示整个数列。
输出格式:
输出共一行,包含 n 个整数,表示排好序的数列。
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
#include <bits/stdc++.h>
using namespace std;
int n;
bool zeng(int a[])
{
int flag=0,i;
for(i=0;i<n-1;i++)
{
if(a[i]>a[i+1])
{
return false;
}
}
return true;
}
void guibing(int a[])
{
int i,j;
for(i=2;!zeng(a);i+=i)
{
for(j=0;j<n;j+=i)
{
sort(a+j,a+min(j+i,n));
}
}
}
int main()
{
int i,m,c,j,k,t,a[100001];
cin>>n;
for(i=0; i<n; i++)
{
cin>>a[i];
}
guibing(a);
for(int x=0; x<n; x++)
{
cout<<a[x]<<" ";
}
cout<<endl;
return 0;
}
31.快速排序
给定一个整数序列,请按非递减序输出采用快速排序(递归法)的各趟排序后的结果。注意:每趟排序以排序区间的首元素为枢轴(支点)。
输入格式:
测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。
输出格式:
对于每组测试,输出若干行,每行是一趟排序后的结果,每行的每两个数据之间留一个空格。
输入样例:
4
8 7 2 1
6
73 49 98 81 64 55
输出样例:
1 7 2 8
1 7 2 8
1 2 7 8
55 49 64 73 81 98
49 55 64 73 81 98
49 55 64 73 81 98
#include <bits/stdc++.h>
using namespace std;
int n;
void kuaipai(int a[],int le,int ri)
{
int l=le,r=ri;
if(l>=r)return;
else
{
int t=a[l];
while(l<r)
{
while(l<r&&a[r]>=t)r--;
a[l]=a[r];
while(l<r&&a[l]<t)l++;
a[r]=a[l];
}
a[l]=t;
for(int x=0; x<n; x++)
{
if(x==0)cout<<a[x];
else
cout<<" "<<a[x];
}
cout<<endl;
kuaipai(a,le,l-1);
kuaipai(a,l+1,ri);
}
}
int main()
{
int i,m,c,j,k,t,a[101];
while(~scanf("%d",&n))
{
for(i=0; i<n; i++)
{
cin>>a[i];
}
kuaipai(a,0,n-1);
}
return 0;
}