1.一元多项式乘法
设计程序求两个一元多项式的和。
输入格式:
输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数。数字间以空格分隔。
输出格式:
输出1行,以指数递降方式输出和多项式非零项的系数和指数(保证不超过整数的表示范围)。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
输入样例:
4 3 4 -5 2 6 1 -2 0
3 5 20 -7 4 3 1
输出样例:
5 20 -4 4 -5 2 9 1 -2 0
#include <stdio.h>
#include <stdlib.h>
typedef struct Node *List;
struct Node
{
int base;
int index;
List next;
};
List Read();
List Add(List L1, List L2);
void PrintList(List L1);
void Attach(int b, int i, List*p);
List mul(List L1, List L2);
int main(void)
{
List P1, P2, P3, P4;
P1 = Read();
P2 = Read();
P3 = Add(P1, P2);
PrintList(P3);
return 0;
}
List Read()
{
List p = (List)malloc(sizeof(struct Node));
p->next = NULL;
List r = p;
int num;
scanf("%d", &num);
while (num--)
{
int base, index;
scanf("%d %d", &base, &index);
Attach(base, index, &r);
}
//r->next = NULL;
List s = p;
p = p->next;
free(s);
return p;
}
List Add(List L1, List L2)
{
if (!L1 || !L2)
{
if (!L1)
{
return L2;
}
else
{
return L1;
}
}
List p1 = L1, p2 = L2;
List p = (List)malloc(sizeof(struct Node));
p->next = NULL;
List rare = p;
while (p1&&p2)
{
if (p1->index == p2->index)
{
int base = p1->base + p2->base;
if (base)
{
int index = p1->index;
Attach(base, index, &rare);
}
p1 = p1->next;
p2 = p2->next;
}
else if (p1->index > p2->index)
{
int index = p1->index;
int base = p1->base;
Attach(base, index, &rare);
p1 = p1->next;
}
else
{
int index = p2->index;
int base = p2->base;
Attach(base, index, &rare);
p2 = p2->next;
}
}
rare->next = p1 ? p1 : p2;
List r = p;
p = p->next;
free(r);
return p;
}
void PrintList(List L1)
{
if (!L1)
{
printf("0 0\n");
return;
}
int flag = 1;
List p = L1;
while (p)
{
if (flag)
{
flag = 0;
}
else
{
printf(" ");
}
int base = p->base;
int index = p->index;
printf("%d %d", base, index);
p = p->next;
}
printf("\n");
}
void Attach(int b, int i, List * p)
{
List k = (List)malloc(sizeof(struct Node));
k->base = b;
k->index = i;
k->next = NULL;
(*p)->next = k;
(*p) = (*p)->next;
}
2.最大子序列和
给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据1:与样例等价,测试基本正确性;
- 数据2:102个随机整数;
- 数据3:103个随机整数;
- 数据4:104个随机整数;
- 数据5:105个随机整数;
输入格式:
输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。
输出格式:
在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。
输入样例:
6
-2 11 -4 13 -5 -2
输出样例:
20
#include <stdio.h>
#include <stdlib.h>
int main()
{
int sum=0,maxsum=0,a,b,i,j,k,x,y,n,m;
int shu[100005];
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&shu[i]);
sum+=shu[i];
if(sum>maxsum)
{
maxsum=sum;
}
else if(sum<0)sum=0;
}
printf("%d",maxsum);
return 0;
}
3. 两个有序链表序列的合并
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。
输入格式:
输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。
输出格式:
在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL
。
输入样例:
1 3 5 -1
2 4 6 8 10 -1
输出样例:
1 2 3 4 5 6 8 10
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
int main()
{
struct node *head1,*head2,*p,*q,*zong,*t1,*t2;
int a,b;
head1=(struct node *)malloc(sizeof(struct node));
head1->next=NULL;
t1=head1;
head2=(struct node *)malloc(sizeof(struct node));
head2->next=NULL;
t2=head2;
zong=(struct node *)malloc(sizeof(struct node));
zong->next=NULL;
while(~scanf("%d",&a))
{
if(a==-1)break;
p=(struct node *)malloc(sizeof(struct node));
p->data=a;
p->next=NULL;
t1->next=p;
t1=p;
}
while(~scanf("%d",&b))
{
if(b==-1)break;
p=(struct node *)malloc(sizeof(struct node));
p->data=b;
p->next=NULL;
t2->next=p;
t2=p;
}
p=head1->next;
q=head2->next;
t1=zong;
while(p&&q)
{
if(p->data>=q->data)
{
t1->next=q;
t1=q;
q=q->next;
}
else
{
t1->next=p;
t1=p;
p=p->next;
}
}
if(p==NULL)
{
t1->next=q;
t1=q;
}
else if(q==NULL)
{
t1->next=p;
t1=p;
}
if(head1->next==NULL&&head2->next==NULL)printf("NULL");
else
for(p=zong->next; p!=NULL; p=p->next)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d\n",p->data);
}
return 0;
}
4.带头节点的双向循环链表操作、
本题目要求读入一系列整数,依次插入到双向循环链表的头部和尾部,然后顺序和逆序输出链表。
链表节点类型可以定义为
typedef int DataType;
typedef struct LinkedNode{
DataType data;
struct LinkedNode *prev;
struct LinkedNode *next;
}LinkedNode;
链表类型可以定义为
typedef struct LinkedList{
int length; /* 链表的长度 */
LinkedNode head; /* 双向循环链表的头节点 */
}LinkedList;
初始化链表的函数可声明为
void init_list(LinkedList *list);
分配节点的函数可声明为
LinkedNode *alloc_node(DataType data);
头部插入的函数可声明为
void push_front(LinkedList *list, DataType data);
尾部插入的函数可声明为
void push_back(LinkedList *list, DataType data);
顺序遍历的函数可声明为
void traverse(LinkedList *list);
逆序遍历的函数可声明为
void traverse_back(LinkedList *list);
输入格式:
输入一行整数(空格分隔),以-1结束。
输出格式:
第一行输出链表顺序遍历的结果,第二行输出逆序遍历的结果。
输入样例:
在这里给出一组输入。例如:
1 2 3 4 5 6 -1
输出样例:
5 3 1 2 4 6
6 4 2 1 3 5
import java.util.Scanner;
// 链表节点
class Node{
int val;
Node pre;
Node next;
Node(int val, Node pre, Node next){
this.val = val;
this.pre = pre;
this.next = next;
}
}
public class Main {
// 头指针作为前置节点
public static Node head = new Node(0, null, null);
public static Node tail = head;
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int n = 0, f = 0;
while((n = cin.nextInt()) != -1) {
if(f++ % 2 == 0) {
addFirst(n);
}else {
addLast(n);
}
}
showPre();
System.out.println();
showPost();
}
// 从头部插入
public static void addFirst(int n) {
Node old = head.next;
Node t = new Node(n, head, old);
head.next = t;
if(head == tail) {
tail = t;
}else {
old.pre = t;
}
}
// 插入尾巴节点
public static void addLast(int n) {
Node t = new Node(n, tail, null);
tail.next = t;
tail = t;
}
// 前序遍历
public static void showPre() {
Node t = head.next;
while(t != null) {
if(t.next == null)
System.out.print(t.val);
else
System.out.print(t.val + " ");
t = t.next;
}
}
// 倒序遍历
public static void showPost() {
Node t = tail;
while(t != head) {
if(t.pre == head)
System.out.print(t.val);
else
System.out.print(t.val + " ");
t = t.pre;
}
}
}
5.进制转换
输入一个十进制的整数。将它转换为二进制数、八进制数和十六进制数。
输入格式:
输入一个不超过100的十进制整数。
输出格式:
在一行内输出对应的二进制数、八进制数和十六进制数,以空格隔开。
输入样例:
在这里给出一组输入。例如:
8
输出样例:
在这里给出相应的输出。例如:
1000 10 8
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[50],b[50],c[50],n,m,i,j,k,d,r,x;
scanf("%d",&n);
if(n!=0)
{
x=m=d=n;
i=0;
while(n)
{
a[i]=n%2;
n=n/2;
if(a[i]<0)a[i]=-a[i];
i++;
}
j=0;
while(d)
{
b[j]=d%8;
d/=8;
if(b[j]<0)b[j]=-b[j];
j++;
}
k=0;
while(m)
{
c[k]=m%16;
m/=16;
if(c[k]<0)c[k]=-c[k];
k++;
}
if(x<0)
{
printf("-");
}
for(r=i-1; r>=0; r--)
{
printf("%d",a[r]);
}
printf(" ");
if(x<0)
{
printf("-");
}
for(r=j-1; r>=0; r--)
{
printf("%d",b[r]);
}
printf(" ");
if(x<0)
{
printf("-");
}
for(r=k-1; r>=0; r--)
{
printf("%d",c[r]);
}
}
else if(n==0)printf("0 0 0");
return 0;
}
6.表达式转换
算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
输入格式:
输入在一行中给出不含空格的中缀表达式,可包含+
、-
、*
、/
以及左右括号()
,表达式不超过20个字符。
输出格式:
在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。
输入样例:
2+3*(7-4)+8/4
输出样例:
2 3 7 4 - * + 8 4 / +
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int IsNum( char c);
int IsZhengfu( char c);
int Compare( char a, char b);
int main()
{
char str1[21];
char str2[21];
int len;
int flag =0;
int i,j;
int space =0;
scanf("%s",str1);
len = strlen(str1);
for( i=0; i<len; i++)
{
if(IsNum(str1[i]))
{
if( space )
{
printf(" ");
space = 0;
}
printf("%c",str1[i]);
}
else if( IsZhengfu(str1[i]) && (i? str1[i-1]=='(':1))
{
if( str1[i]=='-')
{
if(space)
{
printf(" ");
space = 0;
}
printf("%c",str1[i]);
}
}
else
{
if( flag)
{
if( str1[i]==')')
{
while( flag--)
{
if(str2[flag]=='(') break;
printf(" %c",str2[flag]);
}
}
else
{
while( flag )
{
if( Compare( str2[flag-1],str1[i]))
{
printf(" %c",str2[--flag]);
}
else break;
}
str2[flag++] = str1[i];
}
}
else str2[flag++] = str1[i];
for ( j=0; j<flag; j++)
{
if( str2[j]!='(')
{
space = 1;
break;
}
}
}
}
while (flag)
{
printf(" %c",str2[--flag]);
}
return 0;
}
int IsNum( char c)
{
return ( c >='0'&&c<='9')||c=='.';
}
int IsZhengfu( char c)
{
return c=='+' || c=='-';
}
int Compare( char a, char b)
{
if( b==')') return 1;
if( b=='(' || a=='(') return 0;
switch(b)
{
case '+':
case '-':
return 1;
case '*':
case '/':
switch(a)
{
case '+':
case '-':
return 0;
case '*':
case '/':
return 1;
}
}
}
7.冬奥会接驳车
艾灵是冬奥会的一名运动员,今天她准备从奥运村前往比赛场馆进行比赛,本届冬奥会科技感十足,奥组委配备了无人驾驶的接驳车。假定你是奥组委的软件工程师,请你为无人接驳车编写路径规划程序,使其载着艾灵以最短的时间到达目的地。
接驳车的运行范围可以被建模为一张由n行m列单元格组成的地图。有的单元格是空地,可以走;有的单元格处是障碍物,不能走。假定接驳车只可以朝上、下、左、右四个方向行驶,不能斜着走。每行驶过一个位置(单元格)需要1分钟。给定地图以及艾灵的起点和终点,请输出接驳车从起点行驶到终点所需的最短时间。
输入格式:
输入包含多组数据。每组数据第一行是两个整数n和m (1≤ m, n ≤100),表示地图的长和宽;接下来是n行,每行m个数字,表示整个地图。空地格子用0表示,障碍物用1表示,艾灵所在起点用3表示,目的地用4表示。
输出格式:
对于每组数据,如果接驳车能够到达目的地,输出一个整数,表示艾灵从起点到目的地所需的最短时间,如果不能到达目的地,输出“unreachable”。
输入样例:
5 5
1 0 1 1 1
1 0 4 1 0
1 0 0 1 0
0 0 0 1 0
1 0 3 0 1
5 5
3 0 1 1 1
1 0 1 1 0
1 0 1 1 0
0 0 0 1 0
1 0 1 0 4
输出样例:
3
unreachable
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
typedef pair<int, pair<int, int>> PII;
const int N = 110;
int n, m, ans = -1;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
char a[N][N];
bool st[N][N];
int bfs(int x, int y)
{
queue<PII> q;
q.push({0, {x, y}});
st[x][y] = true;
while(q.size())
{
PII t = q.front();
q.pop();
int xx = t.second.first, yy = t.second.second;
if(a[xx][yy] == '4') return t.first;
for(int i = 0; i < 4; i ++ )
{
int nx = xx + dx[i], ny = yy + dy[i];
if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
if(st[nx][ny]) continue;
if(a[nx][ny] == '1') continue;
q.push({t.first + 1, {nx, ny}});
st[nx][ny] = true;
}
}
return -1;
}
int main()
{
int x, y;
cin >> n >> m;
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < m; j ++ )
{
cin >> a[i][j];
if(a[i][j] == '3')
{
x = i, y = j;
}
}
}
ans = bfs(x, y);
if(ans == -1) cout << "unreachable";
else cout << ans ;
}
8.行编辑器
一个简单的行编辑程序的功能是:接受用户从终端输入的程序或数据,并存入用户的数据区。
由于用户在终端上进行输入时,不能保证不出差错,因此,若在编辑程序中,“每接受一个字符即存入用户数据区”的做法显然不是最恰当的。较好的做法是,设立一个输入缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区。允许用户输入出差错,并在发现有误时可以及时更正。例如,当用户发现刚刚键入的一个字符是错的时,可补进一个退格符"#",以表示前一个字符无效;
如果发现当前键入的行内差错较多或难以补救,则可以键入一个退行符"@",以表示当前行中的字符均无效。
如果已经在行首继续输入'#'符号无效。
输入格式:
输入一个多行的字符序列。但行字符总数(包含退格符和退行符)不大于250。
输出格式:
按照上述说明得到的输出。
输入样例1:
在这里给出一组输入。例如:
whli##ilr#e(s#*s)
输出样例1:
在这里给出相应的输出。例如:
while(*s)
输入样例2:
在这里给出一组输入。例如:
outcha@putchar(*s=#++);
输出样例2:
在这里给出相应的输出。例如:
putchar(*s++);
#include <stdio.h>
#include <string.h>
int main()
{
int top, len;
char a[300], b[300];
while (gets(a))
{
top = 0;
for (int i = 0; a[i]; i++)
{
if (a[i] == '#')
{
if (top != 0)
top--;
}
else if (a[i] == '@')
{
if (top != 0)
{
while (top != 0)
top--;
}
}
else
b[top++] = a[i];
}
for (int i = 0; i < top; i++)
{
if (i == top - 1)
printf("%c\n", b[i]);
else
printf("%c", b[i]);
}
}
return 0;
}
9.朋友圈
某学校有N个学生,形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好,形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出,如果A和B是朋友,且B和C是朋友,则A和C也是朋友。请编写程序计算最大朋友圈中有多少人。
输入格式:
输入的第一行包含两个正整数N(≤30000)和M(≤1000),分别代表学校的学生总数和俱乐部的个数。后面的M行每行按以下格式给出1个俱乐部的信息,其中学生从1~N编号:
第i个俱乐部的人数Mi(空格)学生1(空格)学生2 … 学生Mi
输出格式:
输出给出一个整数,表示在最大朋友圈中有多少人。
输入样例:
7 4
3 1 2 3
2 1 4
3 5 6 7
1 6
输出样例:
4
#include <stdio.h>
#include <stdlib.h>
int pre[30005];
int root[30005];
int find(int x){
if(pre[x]!=x){
pre[x] = find(pre[x]);
}
return pre[x];
}
void join(int x,int y){
int fx = find(x);
int fy = find(y);
if(fx!=fy){
pre[fx] = fy;
}
}
int main()
{
int m,n;
scanf("%d %d",&m,&n);
for(int i=1;i<=m;i++){
pre[i] = i;
}
while(n--){
int k,arr[30005];
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d",&arr[i]);
}
for(int i=2;i<=k;i++){
join(arr[1],arr[i]);
}
}
int max = 0;
for(int i=1;i<=m;i++){
int t = find(i);
root[t]++;
if(root[t]>max)max = root[t];
}
printf("%d",max);
return 0;
}
10.部落
在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入格式:
输入在第一行给出一个正整数N(≤104),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:
K P[1] P[2] ⋯ P[K]
其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过104。
之后一行给出一个非负整数Q(≤104),是查询次数。随后Q行,每行给出一对被查询的人的编号。
输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y
,否则输出N
。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2
Y
N
#include <bits/stdc++.h>
using namespace std;
int pre[10005];
int arr[10005];
int sum=0,num=0;
int finde(int x)
{
if(pre[x]==x)
return x;
return pre[x]=finde(pre[x]);
}
void bcj(int x,int y)
{
x=finde(x);
y=finde(y);
if(x==y)
return;
else pre[y]=x;
}
int main()
{
int i,j,k,n,m,c,d;
int t=0;
cin>>n;
for(j=1; j<=10005; j++)
{
pre[j]=j;
}
for(i=0; i<n; i++)
{
cin>>m;
for(j=0; j<m; j++)
{
cin>>arr[j];
if(sum<arr[j])
sum=arr[j];
}
for(j=1; j<m; j++)
{
bcj(arr[0],arr[j]);
}
}
for(i=1;i<=sum;i++)
{
if(pre[i]==i)num++;
}
cout<<sum<<" "<<num<<endl;
cin>>k;
for(i=0; i<k; i++)
{
cin>>c>>d;
if(finde(c)==finde(d))
cout<<"Y"<<endl;
else
cout<<"N"<<endl;
}
return 0;
}
11.串的模式匹配
给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出。如果找不到,则输出“Not Found”。
本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据0:小规模字符串,测试基本正确性;
- 数据1:随机数据,String 长度为 105,Pattern 长度为 10;
- 数据2:随机数据,String 长度为 105,Pattern 长度为 102;
- 数据3:随机数据,String 长度为 105,Pattern 长度为 103;
- 数据4:随机数据,String 长度为 105,Pattern 长度为 104;
- 数据5:String 长度为 106,Pattern 长度为 105;测试尾字符不匹配的情形;
- 数据6:String 长度为 106,Pattern 长度为 105;测试首字符不匹配的情形。
输入格式:
输入第一行给出 String,为由英文字母组成的、长度不超过 106 的字符串。第二行给出一个正整数 N(≤10),为待匹配的模式串的个数。随后 N 行,每行给出一个 Pattern,为由英文字母组成的、长度不超过 105 的字符串。每个字符串都非空,以回车结束。
输出格式:
对每个 Pattern,按照题面要求输出匹配结果。
输入样例:
abcabcabcabcacabxy
3
abcabcacab
cabcabcd
abcabcabcabcacabxyz
输出样例:
abcabcacabxy
Not Found
Not Found
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char zhu[1000005],fu[1000005];
int nextt[1000005];
void nextx(int f)
{
int i=2;
nextt[1]=0;
int j=0;
while(i<=f)
{
while(j!=0&&fu[j+1]!=fu[i])
{
j=nextt[j];
}
if(fu[j+1]==fu[i])
{
j++;
}
nextt[i]=j;
i++;
}
}
int kmp(int l,int f)
{
int i=1,j=0;
while(i<=l)
{
while(j>0&&fu[j+1]!=zhu[i])
{
j=nextt[j];
}
if(fu[j+1]==zhu[i])j++;
if(j==f)
{
return i-j+1;
}
i++;
}
return 0;
}
int main()
{
gets(zhu+1);
int l=strlen(zhu+1);
int n,m,a,v,b,c,i,j,k,f;
scanf("%d",&n);
getchar();
for(i=0; i<n; i++)
{
gets(fu+1);
f=strlen(fu+1);
nextx(f);
m=kmp(l,f);
if(m==0)printf("Not Found\n");
else
{
for(j=m; j<=l; j++)
{
printf("%c",zhu[j]);
}
printf("\n");
}
}
return 0;
}
12.字符串模式匹配
给定主串s和模式串p,编写程序输出p在s中出现的首位置,若p不在s中则输出-1。字符串下标从0开始。
输入格式:
输入为2行,第1行主串s,第2行为模式串p。主串和模式串长度大于4,不超过105。
输出格式:
输出为2行,第1行为3个整数,表示分别在模式串p的m/4、2m/4、3m/4处匹配失败后,模式串下一次匹配的位置,每个整数后一个空格,m表示模式串p的长度;第2行为一个整数,表示p在s中出现的首位置,若p不在s中则输出-1。
输入样例:
qwerababcabcabcabcdaabcabhlk
abcabcabcabc
输出样例:
0 3 6
6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char zhu[1000005],fu[1000005];
int nextt[1000005];
void nextx(int f)
{
int i=2;
nextt[1]=0;
int j=0;
while(i<=f)
{
while(j!=0&&fu[j+1]!=fu[i])
{
j=nextt[j];
}
if(fu[j+1]==fu[i])
{
j++;
}
nextt[i]=j;
i++;
}
}
int kmp(int l,int f)
{
int i=1,j=0;
while(i<=l)
{
while(j>0&&fu[j+1]!=zhu[i])
{
j=nextt[j];
}
if(fu[j+1]==zhu[i])j++;
if(j==f)
{
return i-j+1;
}
i++;
}
return 0;
}
int main()
{
gets(zhu+1);
int l=strlen(zhu+1);
int n,m,a,v,b,c,i,j,k,f;
gets(fu+1);
f=strlen(fu+1);
nextx(f);
m=kmp(l,f);
for(i=1;i<=f;i++)
{
printf("%d ",nextt[i]-1);
}
printf("\n");
printf("%d",m-1);
return 0;
}
13.三元组顺序表表示的稀疏矩阵转置Ⅱ
三元组顺序表表示的稀疏矩阵转置Ⅱ。设a和b为三元组顺序表变量,分别表示矩阵M和T。要求按照a中三元组的次序进行转置,并将转置后的三元组置入b中恰当的位置。
输入格式:
输入第1行为矩阵行数m、列数n及非零元素个数t。
按行优先顺序依次输入t行,每行3个数,分别表示非零元素的行标、列标和值。
输出格式:
按置入b中的顺序输出置入的位置下标,转置后的三元组行标、列标和值,数据之间用空格分隔,共t行。
输入样例1:
3 4 3
0 1 -5
1 0 1
2 2 2
输出样例1:
1 1 0 -5
0 0 1 1
2 2 2 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct pe
{
int i,j;
int da;
} que;
typedef struct r
{
que zu[1001];
int hang,lie,fei;
} qqe;
int main()
{
int n,m,a,v,b,c,i,j,k,f;
qqe ju,zz;
scanf("%d %d %d",&ju.hang,&ju.lie,&ju.fei);
zz.hang=ju.lie;
zz.lie=ju.hang;
zz.fei=ju.fei;
for(i=0; i<ju.fei; i++)
{
scanf("%d %d %d",&ju.zu[i].i,&ju.zu[i].j,&ju.zu[i].da);
}
if(ju.fei)
{
int count=0;
for(k=0; k<ju.lie; k++)
{
for(f=0; f<ju.fei; f++)
{
if(ju.zu[f].j==k)
{
zz.zu[count].i=ju.zu[f].j;
zz.zu[count].j=ju.zu[f].i;
zz.zu[count].da=ju.zu[f].da;
count++;
}
}
}
for(k=0; k<ju.hang; k++)
{
for(f=0; f<ju.fei; f++)
{
if(zz.zu[f].j==k)
{
printf("%d %d %d %d\n",f,zz.zu[f].i,zz.zu[f].j,zz.zu[f].da);
}
}
}
}
return 0;
}
14.列出连通集
给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照"{ v1 v2 ... vk }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。
输入样例:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
#include <bits/stdc++.h>
using namespace std;
#define MAX_MM 999999
int tu[15][15],vis[15];
int n,m;
void DFS(int f)
{
cout<<" "<<f;
int j;
vis[f]=1;
for(j=0;j<n;j++)
if(vis[j]!=1&&tu[f][j]==1)
{
DFS(j);
}
}
void BFS(int f)
{
deque<int> s;
s.push_back(f);
vis[f]=1;
while(s.size()!=0)
{
int t=s.front();
s.pop_front();;
cout<<" "<<t;
for(int i=0;i<n;i++)
{
if(vis[i]!=1&&tu[t][i]==1)
{
s.push_back(i);
vis[i]=1;
}
}
}
}
int main()
{
int i,j,x,y;
cin>>n>>m;
memset(tu,MAX_MM,sizeof tu);
for(i=0;i<m;i++)
{
cin>>x>>y;
tu[x][y]=tu[y][x]=1;
}
for(i=0;i<n;i++)
{
if(vis[i]!=1)
{
cout<<"{";
DFS(i);
cout<<" }"<<endl;
}
}
memset(vis,0,sizeof vis);
for(i=0;i<n;i++)
{
if(vis[i]!=1)
{
cout<<"{";
BFS(i);
cout<<" }"<<endl;
}
}
return 0;
}
15.哈利·波特的考试
哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。
现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。
输入格式:
输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。
输出格式:
输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。
输入样例:
6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80
输出样例:
4 70
#include <bits/stdc++.h>
using namespace std;
int tu[105][105];
int n,m;
int dist[105][105];
int finde(int i)
{
int maxx=0,j;
for(j=1; j<=n; j++)
{
if(dist[i][j]>maxx)maxx=dist[i][j];
}
return maxx;
}
int main()
{
int a,b,c;
int i,j,k;
cin>>n>>m;
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
if(i==j)
{
tu[i][j]=0;
}
else
{
tu[i][j]=9999;
}
}
}
for(i=0; i<m; i++)
{
cin>>a>>b>>c;
tu[a][b]=c;
tu[b][a]=c;
}
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
dist[i][j]=tu[i][j];
}
}
for(k=1; k<=n; k++)
{
for(i=1; i<=n; i++)
{
for(j=1; j<=n; j++)
{
if(dist[i][j]>dist[i][k]+dist[k][j])
{
dist[i][j]=dist[i][k]+dist[k][j];
}
}
}
}
int am=0;
int minn=9999;
for(int i=1; i<=n; i++)
{
int sm=finde(i);
if(sm==9999)
{
cout<<0<<endl;
return 0;
}
else
{
if(minn>sm)
{
minn=sm;
am=i;
}
}
}
cout<<am<<" "<<minn;
return 0;
}
15.旅游规划
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
3 40
#include <bits/stdc++.h>
using namespace std;
#define MAX_MM 999999
int tu[505][505],vis[505],ut[505][505],dis[505],price[505];
int n,m;
int main()
{
int i,j,x,y,z,k,s,d,t;
cin>>n>>m>>s>>d;
memset(tu,MAX_MM,sizeof tu);
memset(ut,MAX_MM,sizeof ut);
memset(dis,MAX_MM,sizeof dis);
memset(price,MAX_MM,sizeof price);
for(i=0; i<m; i++)
{
cin>>x>>y>>z>>k;
tu[x][y]=tu[y][x]=z;
ut[x][y]=ut[y][x]=k;
}
dis[s]=price[s]=0;
vis[s]=1;
for(i=0; i<n; i++)
{
t=s;
int minn=MAX_MM;
for(j=0; j<n; j++)
{
if(vis[j]!=1&&dis[j]<minn)
{
minn=dis[j];
t=j;
}
}
vis[t]=1;
for(j=0; j<n; j++)
{
if(dis[j]>tu[t][j]+dis[t])
{
dis[j]=tu[t][j]+dis[t];
price[j]=ut[t][j]+price[t];
}
else if(dis[j]==tu[t][j]+dis[t])
{
price[j]=min(price[j],price[t]+ut[t][j]);
}
}
}
cout<<dis[d]<<" "<<price[d];
return 0;
}