CSDN话题挑战赛第2期
参赛话题:算法题解
7-1 一元多项式的乘法与加法运算
设计函数分别求两个一元多项式的乘积与和。
输入格式:
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:
输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出
0 0
。输入样例:
4 3 4 -5 2 6 1 -2 0 3 5 20 -7 4 3 1
输出样例:
15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1 5 20 -4 4 -5 2 9 1 -2 0
代码:
#include <iostream> #include <bits/stdc++.h> using namespace std; typedef struct PolyNode *Polynomial;//链表结点的构成 struct PolyNode { int coef;//系数 int expon;//质数 Polynomial link;//指针域 }; Polynomial ReadPoly(); Polynomial Add(Polynomial P1,Polynomial P2); Polynomial Mult(Polynomial P1,Polynomial P2); void PrintPoly(Polynomial P); void Attach(int c,int e,Polynomial *pRear); void Attach(int c,int e, Polynomial *pRear) { Polynomial P; P = (Polynomial)malloc(sizeof(struct PolyNode));//采用先申请空结点的方法 P->coef = c;//对新结点赋值 P->expon = e; P->link = NULL; (*pRear)->link = P;//把新申请的结点P插到pRear后面,指针域移动 *pRear = P;//使pRear指向最后 } Polynomial ReadPoly() { Polynomial P,Rear,t;//Rear表示当前多项式尾部指针,临时变量t是用来储存空结点,之后会被删除 int n; int c,e; scanf("%d",&n); P = (Polynomial)malloc(sizeof(struct PolyNode));//申请链表头空结点 P->link = NULL; Rear = P;//让Rear指向空结点 while(n--) { scanf("%d %d",&c,&e); Attach(c,e,&Rear);//将当前项插入多项式尾部 } t = P;P = P->link;free(t);//删除空(头)结点语句,把空结点用t储存,link指针指向P,继续往下走,然后删除空结点t return P; } Polynomial Add(Polynomial P1,Polynomial P2) { Polynomial P,Rear,t1,t2,t; int sum; t1 = P1; t2 = P2; P = (Polynomial)malloc(sizeof(struct PolyNode)); P->link = NULL; Rear = P;//让Rear指向空结点 while(1) { if(t1 != NULL&&t2 != NULL) { if(t1->expon == t2->expon) { sum = t1->coef + t2->coef; if(sum != 0) Attach(sum,t1->expon,&Rear); t1 = t1->link; t2 = t2->link; } else if(t1->expon > t2->expon) { Attach(t1->coef,t1->expon,&Rear); t1 = t1->link; } else { Attach(t2->coef,t2->expon,&Rear); t2 = t2->link; } } else if(t1 != NULL) { Attach(t1->coef,t1->expon,&Rear); t1 = t1->link; } else if(t2 != NULL) { Attach(t2->coef,t2->expon,&Rear); t2 = t2->link; } else break; } /* while(t1&&t2)//当t1,t2都不空 { if(t1->expon==t2->expon) { sum = t1->coef+t2->coef; if(sum==0) { t1=t1->link; t2=t2->link; } else { Attach(sum,t1->expon,&Rear); t1=t1->link; t2=t2->link; } } if(t1->expon>t2->expon) { Attach(t1->coef,t1->expon,&Rear); t1=t1->link; } if(t1->expon<t2->expon) { Attach(t2->coef,t2->expon,&Rear); t2=t2->link; } } while(t1) { Attach(t1->coef,t1->expon,&Rear); t1=t1->link; } while(t2) { Attach(t2->coef,t2->expon,&Rear); t2=t2->link; } */ Rear->link = NULL; t=P;P=P->link;free(t);//删除空结点 return P; } Polynomial Mult(Polynomial P1,Polynomial P2) { Polynomial P,Rear,t1,t2,t; int c,e; if(!P1||!P2) return NULL; t1 = P1;t2 = P2; P = (Polynomial)malloc(sizeof(struct PolyNode)); P->link = NULL; Rear = P; while(t2)//先用P1的第一项乘以P2 { Attach(t1->coef*t2->coef,t1->expon+t2->expon,&Rear); t2 = t2->link; } t1 = t1->link; while(t1) { t2 = P2; Rear = P; while(t2) { c = t1->coef*t2->coef; e = t1->expon+t2->expon; while(Rear->link&&Rear->link->expon>e)//要插入的与链表中的比较,如果比链表中的小,就将Rear后移 Rear = Rear->link; if(Rear->link&&Rear->link->expon == e)//如果相等 { if(Rear->link->coef + c)//加起来不等于0的话就直接系数累加 Rear->link->coef += c; else//等于0的话直接删掉即可 { t = Rear->link; Rear->link = t->link; free(t); } } else//要插入的与链表中的比较,如果比链表中的大,就要构造空结点 { t = (Polynomial)malloc(sizeof(struct PolyNode)); t->coef = c;t->expon = e; t->link = Rear->link;//插入操作 Rear->link = t;Rear = Rear->link; } t2 = t2->link; } t1 = t1->link; } t2 = P;P = P->link;free(t2);//删除刚开始构建的空结点 return P; } void PrintPoly(Polynomial P) { int flag = 0; if(!P) { printf("0 0\n"); return ; } while(P) { if(!flag) flag = 1; else printf(" "); printf("%d %d",P->coef,P->expon); P = P->link; } printf("\n"); } int main() { Polynomial P1,P2,PP,PS; P1 = ReadPoly(); P2 = ReadPoly(); PP = Mult(P1,P2);//乘法 PrintPoly(PP); PS = Add(P1,P2);//加法 PrintPoly(PS); return 0; }
7-2 一元多项式求导
设计函数求一元多项式的导数。
输入格式:
以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:
以与输入相同的格式输出导数多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。
输入样例:
3 4 -5 2 6 1 -2 0
输出样例:
12 3 -10 1 6 0
代码:
#include <iostream>
using namespace std;
int main()
{
int m,n;
int flag = 1;
while(cin>>m>>n)
{
if(n!=0)
{
if(!flag)
{
cout<<" ";
}
cout<<m*n<<" "<<n-1;
flag = 0;
}
else
continue;
}
if(flag)
cout<<0<<" "<<0;
}
7-3 银行业务队列简单模拟
设某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。给定到达银行的顾客序列,请按业务完成的顺序输出顾客序列。假定不考虑顾客先后到达的时间间隔,并且当不同窗口同时处理完2个顾客时,A窗口顾客优先输出。
输入格式:
输入为一行正整数,其中第1个数字N(≤1000)为顾客总数,后面跟着N位顾客的编号。编号为奇数的顾客需要到A窗口办理业务,为偶数的顾客则去B窗口。数字间以空格分隔。
输出格式:
按业务处理完成的顺序输出顾客的编号。数字间以空格分隔,但最后一个编号后不能有多余的空格。
输入样例:
8 2 1 3 9 4 11 13 15
输出样例:
1 3 2 9 11 4 13 15
#include<iostream>
#include<queue>
using namespace std;
int main(){
queue<int>qa;
queue<int>qb;
int n,data;
cin>>n;
while(n--){
cin>>data;
if(data%2)
qa.push(data);
else
qb.push(data);
}bool isfirst=true;//控制格式
while((!qa.empty())||(!qb.empty())){
//a窗口处理速度是b窗口的两倍所以先出队a(2个)
int times=2;
while((!qa.empty())&×--){
if(isfirst){
cout<<qa.front();//输出a队首元素
isfirst=false;
}else{
cout<<" "<<qa.front();
}qa.pop();//出队
}if(!qb.empty()){
if(isfirst){
cout<<qb.front();//输出b队首元素
isfirst=false;
}else{
cout<<" "<<qb.front();
}qb.pop();//出队
}
}return 0;
}
7-5 银行排队问题之单队列多窗口服务
假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。
输入格式:
输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T
和事务处理时间P
,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。这里假设每位顾客事务被处理的最长时间为60分钟。
输出格式:
在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。
输入样例:
9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3
输出样例:
6.2 17 61
5 3 1
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
struct node
{
int t, p;
};
int main()
{
int n;
cin>>n;
queue <node> q;
int i;
for(i = 0; i < n; i++)
{
node tmp;
cin>>tmp.t>>tmp.p;
if(tmp.p > 60) tmp.p = 60;
q.push(tmp);
}
int k;
cin>>k;
int win[15] = {0}, num[15] = {0};
int wait = 0, maxn = 0, sum = 0;
while(!q.empty())
{
int flag = 0;
int minn = 0x3f3f3f3f, imin = 0;
for(i = 0; i < k; i++)
{
if(win[i] <= q.front().t)
{
win[i] = q.front().t + q.front().p;
num[i]++;
flag = 1;
q.pop();
break;
}
if(minn > win[i])
{
minn = win[i];
imin = i;
}
}
if(flag == 0)
{
wait = win[imin] - q.front().t;
win[imin] += q.front().p;
if(maxn < wait) maxn = wait;
sum += wait;
num[imin]++;
q.pop();
}
}
int last = win[0];
for(i = 0; i < k; i++)
{
if(win[i] > last) last = win[i];
}
printf("%.1lf %d %d\n", sum * 1.0 / n * 1.0, maxn, last);
for(i = 0; i < k; i++)
{
cout<<num[i];
if(i != k - 1) cout<<" ";
else cout<<endl;
}
return 0;
}
7-6 银行排队问题之单队列多窗口加VIP服务
假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。
有些银行会给VIP客户以各种优惠服务,例如专门开辟VIP窗口。为了最大限度地利用资源,VIP窗口的服务机制定义为:当队列中没有VIP客户时,该窗口为普通顾客服务;当该窗口空闲并且队列中有VIP客户在等待时,排在最前面的VIP客户享受该窗口的服务。同时,当轮到某VIP客户出列时,若VIP窗口非空,该客户可以选择空闲的普通窗口;否则一定选择VIP窗口。
本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间,并且统计每个窗口服务了多少名顾客。
输入格式:
输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T
、事务处理时间P
和是否VIP的标志(1是VIP,0则不是),并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10)—— 为开设的营业窗口数,以及VIP窗口的编号(从0到K−1)。这里假设每位顾客事务被处理的最长时间为60分钟。
输出格式:
在第一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。
在第二行中按编号递增顺序输出每个窗口服务了多少名顾客,数字之间用1个空格分隔,行末不能有多余空格。
输入样例:
10
0 20 0
0 20 0
1 68 1
1 12 1
2 15 0
2 10 0
3 15 1
10 12 1
30 15 0
62 5 1
3 1
输出样例:
15.1 35 67
4 5 1
#include <bits/stdc++.h>
struct consumer
{
double arrive;
double process;
double start;
double end;
double wait;
int vip;
int skip;
}c[1001];
struct windows
{
int count;
int availiable;
double end;
}w[11];
using namespace std;
int main()
{
memset(c,0,sizeof(c));
memset(w,0,sizeof(w));
int n,k,arrive,process,vip;
cin>>n;
for (int i=0;i<n;i++)
{
cin>>arrive>>process>>vip;
if (process>60) process=60;
c[i].arrive=arrive;
c[i].process=process;
c[i].vip=vip;
}
int v;
cin>>k>>v;
for (int i=0;i<k;i++) w[i].availiable=1;
int count=0;
int m;
for (m=0;;m++)
{
if (count==n) break;
for (int i=0;i<k;i++) //窗口刷新
{
if (w[i].end==m)
{
w[i].availiable=1;
}
}
if (w[v].availiable==1) //vip窗口拉人
{
for (int i=0;c[i].arrive<=m&&i<n;i++)
{
if (c[i].skip==1) continue;
if (c[i].vip==1)
{
c[i].skip=1;
c[i].start=m;
c[i].end=c[i].start+c[i].process;
c[i].wait=c[i].start-c[i].arrive;
w[v].availiable=0;
w[v].end=m+c[i].process;
count++;
w[v].count++;
break;
}
}
}
for (int i=0;i<k;i++)
{
if (w[i].availiable==1)
{
for (int j=0;j<n&&c[j].arrive<=m;j++)
{
if (c[j].skip==1) continue;
c[j].start=m;
c[j].end=c[j].start+c[j].process;
c[j].skip=1;
c[j].wait=c[j].start-c[j].arrive;
w[i].availiable=0;
w[i].count++;
w[i].end=m+c[j].process;
count++;
break;
}
}
}
}
double sum=0;
int maxwait=-1,last=-1;
for (int i=0;i<n;i++)
{
sum+=c[i].wait;
if (c[i].wait>maxwait)
{
maxwait=c[i].wait;
}
if (c[i].end>last)
{
last=c[i].end;
}
// printf("*%.1lf %.1lf %.1lf\n",c[i].start,c[i].process,c[i].end);
}
printf("%.1lf %d %d\n",sum/n,maxwait,last);
printf("%d",w[0].count);
for (int i=1;i<k;i++)
{
printf(" %d",w[i].count);
}
return 0;
}
7-7 修理牧场
农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的、能锯成N块的木头,即该木头的长度是Li的总和。
但是农夫自己没有锯子,请人锯木的酬金跟这段木头的长度成正比。为简单起见,不妨就设酬金等于所锯木头的长度。例如,要将长度为20的木头锯成长度为8、7和5的三段,第一次锯木头花费20,将木头锯成12和8;第二次锯木头花费12,将长度为12的木头锯成7和5,总花费为32。如果第一次将木头锯成15和5,则第二次锯木头花费15,总花费为35(大于32)。
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(≤104),表示要将木头锯成N块。第二行给出N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;//greater是从小到大排列,符合这个过程
int main()
{
int n,x;
cin>>n;
for(int i = 0;i < n;i++)
{
cin>>x;
q.push(x);
}
int sum = 0;
while(q.size() > 1)//q中的元素(结点)多于一个的时候执行这个循环
{
int a = q.top();
q.pop();
int b = q.top();
q.pop();
sum += (a + b);//合并两个最小的
q.push(a+b);
}
cout<<sum<<endl;
}
7-8 目录树
在ZIP归档文件中,保留着所有压缩文件和目录的相对路径和名称。当使用WinZIP等GUI软件打开ZIP归档文件时,可以从这些信息中重建目录的树状结构。请编写程序实现目录的树状结构的重建工作。
输入格式:
输入首先给出正整数N(≤104),表示ZIP归档文件中的文件和目录的数量。随后N行,每行有如下格式的文件或目录的相对路径和名称(每行不超过260个字符):
- 路径和名称中的字符仅包括英文字母(区分大小写);
- 符号“\”仅作为路径分隔符出现;
- 目录以符号“\”结束;
- 不存在重复的输入项目;
- 整个输入大小不超过2MB。
输出格式:
假设所有的路径都相对于root目录。从root目录开始,在输出时每个目录首先输出自己的名字,然后以字典序输出所有子目录,然后以字典序输出所有文件。注意,在输出时,应根据目录的相对关系使用空格进行缩进,每级目录或文件比上一级多缩进2个空格。
输入样例:
7
b
c\
ab\cd
a\bc
ab\d
a\d\a
a\d\z\
输出样例:
root
a
d
z
a
bc
ab
cd
d
c
b
#include <stdio.h>
#include<stdlib.h>
#include <string.h>
typedef int Bool;
typedef struct node *Node;
struct node {
char*Name;
Bool isMulu;//先判断是不是目录,是目录才有file和mulu,否则只可能有brother
Node File;//指示本目录的子目录
Node Mulu;//指示本目录的子文件
Node Brother;//指示和本目录或文件平行的目录或文件
} Head;
void Print(Node,int);
void Read();
Node New(char*);
Node InsertMulu(Node,char*);
Node InsertFile(Node,char*);
int main() {
// printf("%d",strlen("12"));
int n;
scanf("%d",&n);
Head.Name=(char*)malloc(sizeof(char)*5);
strcpy(Head.Name,"root");
Head.File=NULL;
Head.Mulu=NULL;
Head.Brother=NULL;
Head.isMulu=1;
for(int i=0; i<n; i++) {
getchar();
Read();
// printf("-%p-",Head);
// Print(Head.Son,0);
}
Print(&Head,0);
return 0;
}
void Read() {
char FileName[261];
Node temp=&Head;
scanf("%s",FileName);
// printf("[%s]",FileName);
char words[261];
int j,L=0;
for(int i=0; i<strlen(FileName); i++) {
if(FileName[i]=='\\') {
for(j=L; j<i; j++) {
words[j-L]=FileName[j];
}
words[j-L]='\0';
// printf("(%s)",words);
temp->Mulu=InsertMulu(temp->Mulu,words);
temp=temp->Mulu;
while(strcmp(temp->Name,words))temp=temp->Brother;
L=i+1;
}
}
if(L<strlen(FileName)) {
for(j=L; j<=strlen(FileName); j++) {
words[j-L]=FileName[j];
}
// printf("(%s)",words);
temp->File=InsertFile(temp->File,words);
}
}
Node InsertMulu(Node H,char*K) {
if(!H||strcmp(H->Name,K)>0) {
Node temp=New(K);
temp->Brother=H;
return temp;
}
if(strcmp(H->Name,K)==0)return H;
H->Brother=InsertMulu(H->Brother,K);
return H;
}
Node InsertFile(Node H,char*K) {
if(!H||strcmp(H->Name,K)>0) {
Node temp=New(K);
temp->isMulu=0;
temp->Brother=H;
return temp;
}
H->Brother=InsertFile(H->Brother,K);
return H;
}
Node New(char*K) {
Node temp=(Node)malloc(sizeof(struct node));
temp->Name=(char*)malloc(sizeof(char)*(strlen(K)+1));
strcpy(temp->Name,K);
temp->Brother=NULL;
temp->File=NULL;
temp->Mulu=NULL;
temp->isMulu=1;//默认是在建目录
return temp;
}
void Print(Node H,int Space) {
if(H) {
for(int i=0; i<Space; i++)printf(" ");
printf("%s\n",H->Name);
if(H->isMulu==1)
Print(H->Mulu,Space+2);
Print(H->File,Space+2);
Print(H->Brother,Space);
}
}