题目1:杭电实验室会定期去电影院看电影,按照惯例,每个成员需要先抽一个号码。
给出n个人的名字,各抽取一个数字, 自己用一种数据结构存取人的名字和抽取数字信息(票数)
例如:BOB 9 Alice 12 Tom 5 jack 7 Nick 4…
1.定义一种数叫丑数,其因子除1外只有2.3.5的倍数,(例如4,10,是丑数,11,13不是),输出所有抽到丑数的人的名字
2. 根据个人所抽数字大小升序排序, 输出排序后的所有名字
3.现有一个新名字加入,将名字插入所有名字中间(n/2)处,并排序输出所有名字
5
BOB 9 Alice 12 Tom 5 jack 7 Nick 4
*
//题目中有插入操作,可以选择链表,但是又有排序操作,只有直接插入排序可以对链表进行处理
//所以选用静态链表 动态链表之所以是动态的,是因为需要指针去建立联系
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100;
struct node{
char id[10];
int num,adress;
int next;//指针域
bool flag;//表示该数是丑数,即在链表上
// int order;//记录有效节点在链表上的序号
}stu[maxn];
bool cmp(node a,node b){
if(a.flag!=b.flag) return a.flag>b.flag;
else return a.num<b.num;
}
bool isugly(int num){
while(num%2==0){
num=num/2;
}
while(num%3==0){
num=num/3;
}
while(num%5==0){
num=num/5;
}
//去除完所有2,3,5的因子之后
if(num==1) return true;
else return false;
}
int main(){
for(int i=0;i<maxn;i++){
stu[i].flag=false;
}
int n,data;
int count=0;//记录丑数个数
char str[20];
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%s %d",stu[i].id,&stu[i].num);
stu[i].adress=i;
if(isugly(stu[i].num)){//是丑数的话将其标注
stu[i].flag=true;
count++;
printf("%s ",stu[i].id);//输出所有抽到丑数的人的名字
}
}
printf("\n");
sort(stu,stu+maxn,cmp);
printf("排序后的所有是丑数的名字:\n");
for(int i=0;i<count;i++){
printf("%s ",stu[i].id);//排序后输出所有是丑数的人的名字
if(i!=count-1){
stu[i].next=i+1;
}else{
stu[i].next=-1; //最后一个结点的指针域设为-1
}
}
printf("\n");
//插入一个名字结束
char name[10];
printf("Please input a name:\n");
scanf("%s",name);
for(int i=0;i<count/2;i++){
printf("%s ",stu[i].id);//输出前一半所有人的名字
}
printf("%s ",name);
for(int i=count/2;i<count;i++){
printf("%s ",stu[i].id);//输出前一半所有人的名字
}
/*这个是错误的,因为连接地址自己设的不对 ,只有插入一个名字的时候,才是对的,
//可以添加多个名字都是在中间,新来的放在末尾
while(printf("Please input a name,end表示结束:\n"),scanf("%s",stu[count].id),stu[count].id!="end"){
stu[count].adress=count;
stu[count/2-1].next=count;
stu[count].next=count/2;
count++;//统计所有人数
for(int p=0;p!=-1;p=stu[p].next){
printf("%s ",stu[p].id);//输出所有人的名字
}
printf("\n");
}
return 0;
}
第二题是图像处理的题,直接放弃
第三题:
瓜农王大爷去年种西瓜赚了不少钱。看到收入不错,今年他又重新开辟了n个西瓜地。
为了能给他的n个西瓜地顺利的浇上水,对于每个西瓜地他可以选择在本地打井,也可以修管道从另一个瓜地(这个瓜地可能打了井;也可能没打井,他的水也是从其他瓜地引来的)将水引过来。
当然打井和修管道的费用有差别。已知在第i个西瓜地打井需要耗费wi元,在第i、j个西瓜地之间修管道需要耗费pi,j元。
现在的问题是:王大爷要想使所有瓜地都被浇上水,至少需要花费多少钱(打井与修管道的费用和)?
由于瓜地较多,王大爷无法选择在哪些(个)瓜地打井,哪些西瓜地之间修管道。
请你编程帮王大爷做出决策,求出最小费用。
输入格式
第1行,一个正整数n,代表西瓜地的数量。
以下n行,依次给出整数w1…wn(每块西瓜地的打井费用)。
紧接着是一个nn的整数矩阵,矩阵的第i行第j列的数代表pi,j(两块西瓜地之间建立管道的费用)。每行的两个数之间有一个空格隔开。*
//最小生成树是整个图所有路径之和最小,而最短路径是两点之间路径最短,所以此题是最小生成树
//最小生成树有prim和kruskal,prim算法时间复杂度O(v^2),适合顶点数较少,边较多的稠密图,
//kruskal算法O(ElogE),适合稀疏图,边少 一般来说两个算法都可以,此题看这边数很多,我们就选prim算法
//prim算法与Dijkstral类似,Kruskal会用到并查集
/*
思考:本题如果单求出最小生成树,即边的权值之和最小,不一定符合题意,因为题目中还的用上点权,看解答图也知道左小生成树要求
这个图连通,可解答中明明是两个连通分量。
这里想的方法是:依然求出最小生成树,这是所有边权最小的边,然后将其中的一条边与两个顶点的最小点权
比较,如果这条边小于等于它,那么这条边保留,否则取两个顶点的最小点权代替这条边得权值,但是这样不一定能保证图联通
再次审视一下这道题,有一个不同的点是点权值也需要考虑在内,但是prim和Kruskal都是只对边权进行处理,
百度之后看到可以在加一个点,然后将其各个点的点权变为各个点到新点的边,相当于又加了6条边,这样
包括这个点算在内,如果收录的边是一个点与这个点相连的边,就相当于是在这个点上挖了一口井。
/
/
6
5
4
4
3
1
20
0 2 2 2 9 9
2 0 3 3 9 9
2 3 0 4 9 9
2 3 4 0 9 9
9 9 9 9 0 9
9 9 9 9 9 0
/
/
//因为给出的是矩阵存储边的信息,所以直接用prim算法输入会稍微简单些
//prim算法
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=100000000;
const int maxv=1000;
int n,G[maxv][maxv];//顶点数,存储边信息的二维矩阵
bool vis[maxv]={false};
int d[maxv];
int prim(){
fill(d,d+maxv,INF);
d[0]=0;
int ans=0;
for(int i=0;i<=n;i++){
int u=-1,MIN=INF;
for(int j=0;j<=n;j++){
if(vis[j]==false && d[j]<MIN){
u=j;
MIN=d[j];
}
}
if(u==-1) return -1;//图不连通,返回-1
vis[u]=true;
ans+=d[u];
for(int v=0;v<=n;v++){
//如果该顶点未访问过,且u可以到达v,且以u为接口让u的邻接点距离集合更近
if(vis[v]==false && G[u][v]!=0 && G[u][v]<d[v]){
d[v]=G[u][v];
}
}
}
return ans;
}
int main(){
int w[maxv];
// fill(G[0],G[0]+maxv*maxv,INF);//将图初始化为全部最大,不初始化也可以,未赋值默认为0
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&w[i]);
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&G[i][j]);
// if(G[i][j]==0){//因为每次要挑选
// G[i][j]=INF;
// }
}
}
//增加了一个新的顶点 ,将每个顶点的权值变成边
for(int i=0;i<n;i++){
G[n][i]=G[i][n]=w[i];
}
// G[n][n]=0;
int ans=prim();
printf("%d\n",ans);
return 0;
}
//Kruskal算法:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxv=1000;
const int maxe=300;
int father[maxv];
int n,G[maxv][maxv];//n个顶点
int total_edge=0;//边的总数
struct edge{
int u,v;
int cost;
}E[maxe];
bool cmp(edge a,edge b){
return a.cost<b.cost;
}
int findFather(int x){
int a=x;
while(x!=father[x]){
x=father[x];
}
//路径压缩
while(a!=father[a]){
int z=a;
father[a]=x;
a=father[a];
}
}
int Kruskal(){
int ans=0,num_edge=0;
for(int i=0;i<=n;i++){//n+1个顶点
father[i]=i;
}
sort(E,E+total_edge,cmp);//所有边按权从小到大排序
for(int i=0;i<total_edge;i++){
int fau=findFather(E[i].u);
int fav=findFather(E[i].v);
if(fau!=fav){//不在同一个连通块中
father[fau]=fav;//将其放入同一个连通块中
ans+=E[i].cost;//将该边加入最小生成树
num_edge++;
if(num_edge==n) break;//又加了一个顶点,所以n+1个顶点最小生成树应该有n条边
}
}
if(num_edge!=n) return -1;//图不连通返回-1
else return ans;
}
int main(){
scanf("%d",&n);
int temp;//暂时存储点权
//多了6条边,是从i到n
for(int i=0;i<n;i++){
scanf("%d",&temp);
E[total_edge].u=i;
E[total_edge].v=n;
E[total_edge].cost=temp;
total_edge++;
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&G[i][j]);
if(i<j){//只需要上三角
E[total_edge].u=i;
E[total_edge].v=j;
E[total_edge].cost=G[i][j];
total_edge++;
}
}
}
int ans=Kruskal();
printf("%d\n",ans);
return 0;
}