【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。
【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd...的默认顺序给出。然后是某字符串和某01序列。
【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。
【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。
【样例输入】
8
5 29 7 8 14 23 3 11aabchg
00011110111111001
【样例输出】
0001
10
1110
1111
110
01
0000
001000100011011100010000
acdef
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<cmath> #define MAX 1000 using namespace std; typedef struct halftree { int weight; int Lchild; int Rchild; int parent; }HalfNode,Halftree[MAX+1]; void Find(Halftree ht,int cur,int &s1,int &s2)//找到没有双亲的最小两个权数 { s1=s2=0; int min1,min2; min1=min2=9999; for(int i=1;i<=cur;i++) { if(ht[i].parent!=0) continue; if(ht[i].weight<min1) { min2=min1;s2=s1; min1=ht[i].weight;s1=i; } else if(ht[i].weight<min2) { min2=ht[i].weight; s2=i; } } } void CreateHalftree(Halftree ht,int n)//创建哈夫曼树 { for(int i=n+1;i<=2*n-1;i++) { int s1,s2; typedef char *HalfCode[n+1]; Find(ht,i-1,s1,s2); ht[i].weight=ht[s1].weight+ht[s2].weight; ht[i].Lchild=s1; ht[i].Rchild=s2; ht[s1].parent=i; ht[s2].parent=i; ht[i].parent=0; } } typedef char *HalfCode[MAX+1]; void CreateCode(Halftree ht,HalfCode hc,int n)//创建哈夫曼编码 { char *cd;//用来临时储存每一个编码值 cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0'; for(int i=1;i<=n;i++) { int start=n-2; int child=i;int parent=ht[i].parent; while(parent!=0) { if(ht[parent].Lchild==child) cd[start--]='0'; else cd[start--]='1'; child=parent; parent=ht[child].parent; } hc[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(hc[i],&cd[++start]);//注意start要++!!! //cout<<hc[i]<<endl; } free(cd); } void print(HalfCode hc,char ch1[],char ch2[],int n) { for(int i=1;i<=n;i++) { cout<<hc[i]<<endl; } for(int i=0;ch1[i]!='\0';i++)//字母转编码 { int j=ch1[i]-'a'+1; cout<<hc[j]; } cout<<endl; char ch[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; int j=0; while(ch2[j]!='\0') { char mid[MAX]; int x=0; bool flag=false; for(int i=j;ch2[i]!='\0';i++) { mid[x++]=ch2[i]; mid[x]='\0'; for(int y=1;y<=n;y++) { if(strcmp(hc[y],mid)==0) { cout<<ch[y-1]; flag=true; break; } } if(flag) { j=i+1; break; } } } } int main() { int n; cin>>n; Halftree ht; for(int i=1;i<=n;i++) { int weight; cin>>weight; ht[i].parent=0; ht[i].weight=weight; } CreateHalftree(ht,n); HalfCode hc; CreateCode(ht,hc,n); char ch1[MAX],ch2[MAX]; cin>>ch1; cin>>ch2; print(hc,ch1,ch2,n); // cout<<1<<endl; }
注释:哈夫曼创建+编码分三步:
1.建立结构体,初始化叶结点(parent=0,输入weight)
2.创建哈夫曼树:贪心找最小两个权值,自下向上创建树,更新parent和Lchild和Rchild的值
3.编码:用指针数组储存每个字符串编码的头指针。树是自下向上直到根结点,临时字符串是自右向左录入01值,注意start最后要++。
此题必须采用邻接表的存储结构,建立图的存储,然后采用DFS遍历实现求解。否则不给分。
警察抓到了 n 个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从 1 至 n。
【输入】
第一行:n(<=1000,罪犯数量),第二行:m(<5000,关系数量)以下若干行:每行两个数:I 和 j,中间一个空格隔开,表示罪犯 i 和罪犯 j 相互认识。
【输出】
一个整数,犯罪团伙的数量。
【样例输入】
11
8
1 2
4 3
5 4
1 3
5 6
7 10
5 10
8 9
【输出】
3
#include <iostream> #include<stdlib.h> using namespace std; #define MAX 1000 typedef struct ArcNode//用来表示每个点的邻接点 { int adj; struct ArcNode *next; }ArcNode; typedef struct VertexNode//用来表示每个点 { int data; ArcNode *first;//每个点的第一个邻接点的指针 }VertexNode; typedef struct adjlist { VertexNode vertex[MAX+1]; int vexnum,arcnum; }AdjList; int visit[1000]={0}; bool judge(int n) { int s=0; for(int i=1;i<=n;i++) { if(visit[i]==1) s++; } if(s==n) return true; else return false; } void DFS(AdjList aj,int v0)//深度搜索 { visit[v0]=1; ArcNode *p=aj.vertex[v0].first; while(p!=NULL) { if(!visit[p->adj]) { DFS(aj,p->adj); } p=p->next; } } void print(AdjList aj,int n) { int v0=1; int num=0; while(!judge(n)) { DFS(aj,v0); for(int i=1;i<=n;i++) { if(visit[i]!=1) { v0=i; break; } } num++; } cout<<num<<endl; } int main() { int n,m; cin>>n; cin>>m; AdjList aj; for(int i=1;i<=n;i++)//初始化邻接表 { aj.vertex[i].first=new ArcNode; aj.vertex[i].first=NULL; } for(int i=1;i<=m;i++)//建立邻接表 { int a,b; cin>>a>>b; aj.vertex[a].data=a; ArcNode *p=NULL; ArcNode *q=aj.vertex[a].first; p=new ArcNode; p->adj=b; p->next=NULL; if(aj.vertex[a].first==NULL) { aj.vertex[a].first=p; } else { while(q->next!=NULL) { q=q->next; } q->next=p; } aj.vertex[b].data=b; ArcNode *pp=NULL,*qq=aj.vertex[b].first; pp=new ArcNode; pp->adj=a; pp->next=NULL; if(aj.vertex[b].first==NULL) { aj.vertex[b].first=pp; } else { while(qq->next!=NULL) { qq=qq->next; } qq->next=pp; } } // cout<<1<<endl; print(aj,n); }
注释:邻接表+深度搜索遍历图,注意邻接表创建是分配空间问题
根据输入的图的邻接矩阵A,判断此图的连通分量的个数。请使用邻接矩阵的存储结构创建图的存储,并采用BFS优先遍历算法实现,否则不得分。
【输入形式】
第一行为图的结点个数n,之后的n行为邻接矩阵的内容,每行n个数表示。其中A[i][j]=1表示两个结点邻接,而A[i][j]=0表示两个结点无邻接关系。
【输出形式】
输出此图连通分量的个数。
【样例输入】
5
0 1 1 0 0
1 0 1 0 0
1 1 0 0 0
0 0 0 0 1
0 0 0 1 0
【样例输出】
2
【样例说明】
邻接矩阵中对角线上的元素都用0表示。(单个独立结点,即与其它结点都没有边连接,也算一个连通分量)#include <iostream> #include<stdlib.h> using namespace std; typedef struct adjmartrix { int arcs[50][50]; int vexnum; }AdjMaatrix; typedef struct queue1 { int vex[100]; int first; int last; }Queue; int pop(Queue &a) { if(a.first==a.last) exit(0); else { a.first++; return a.vex[a.first-1]; } } void push(Queue &a,int b) { if(a.last==100) exit(0); else { a.vex[a.last]=b; a.last++; } } bool judge(int visit[],int n) { int s=0; for(int i=1;i<=n;i++) { if(visit[i]==1) s++; } if(s==n) return true; else return false; } void BFS(AdjMaatrix gn,int n,int v0)//邻接矩阵+广搜遍历图 { int visit[n+1]; for(int i=1;i<=n;i++) visit[i]=0; visit[v0]=1; int num=0; while(!judge(visit,n)) { Queue a; a.first=a.last=0; push(a,v0); while(a.first!=a.last) { int p=pop(a); for(int i=1;i<=n;i++) { if(gn.arcs[p][i]==1&&!visit[i])//两点关联并且没有广搜到过 { push(a,i); visit[i]=1; } } } for(int i=1;i<=n;i++)//查找另外一个连通子图 { if(visit[i]!=1) { v0=i; visit[v0]=1; break; } } num++; } cout<<num<<endl; } int main() { int n; cin>>n; AdjMaatrix gn; bool flag=true; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cin>>gn.arcs[i][j]; if(gn.arcs[i][j]!=0) flag=false; } } gn.vexnum=n; /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) cout<<gn.arcs[i][j]<<" "; cout<<endl; }*/ if(flag) { cout<<n<<endl; } else BFS(gn,n,1); return 0; }
注释:邻接矩阵+广搜(BFS),邻接矩阵找关联点只需先定行(某个点),再依次遍历每一列(其他点)即可。
【问题描述】
已知含有n个顶点的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出,只给出不包括主对角线元素在内的下三角形部分的元素,且不包括不相邻的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
第一行给出结点个数n和三元组的个数count,以下每行给出一个三元组,数之间用空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
求解的最小生成树的各条边、边的权值之和
【样例输入】
5 8
2 1 7
3 1 6
3 2 8
4 1 9
4 2 4
4 3 6
5 2 4
5 4 2
【样例输出】1-3:6
3-4:6
4-5:2
4-2:4
18【样例说明】
权值是正整数,可能很大,但不需要考虑整型溢出问题#include <iostream> using namespace std; #define MAX 20//点的最大个数 int judge[MAX]={0}; typedef struct arcnode { int adj;//权值 } ArcNode; typedef struct adjmatrix { ArcNode arcs[MAX][MAX]; char vertex[MAX]; int vexnum,arcnum; }AdjMatrix; struct { int adjvex; int lowcost; }closedge[MAX+1]; int Min(AdjMatrix gn) { int min=25897; int c; for(int i=1;i<=gn.vexnum;i++) { if(min>closedge[i].lowcost&&closedge[i].lowcost!=0) { min=closedge[i].lowcost; c=i; } } return c; } void Mintree(AdjMatrix gn,int u) { int sum=0; closedge[u].lowcost=0;//初始化U={u} for(int i=1;i<=gn.vexnum;i++)//先把起点与各点关系以及距离记录下来 { if(i!=u)//防止重复 { closedge[i].adjvex=u;//表示将两个点关联,i点与u点关联 closedge[i].lowcost=gn.arcs[u][i].adj;//表示u,i之间的距离(权值) } } for(int e=1;e<=gn.vexnum-1;e++) { int v=Min(gn); u=closedge[v].adjvex; cout<<u<<"-"<<v<<":"; cout<<closedge[v].lowcost<<endl; sum+=closedge[v].lowcost; closedge[v].lowcost=0; for(int i=1;i<=gn.vexnum;i++) { if(gn.arcs[v][i].adj<closedge[i].lowcost) { closedge[i].lowcost=gn.arcs[v][i].adj; closedge[i].adjvex=v; } } } cout<<sum<<endl; } int main() { int n,Count; cin>>n>>Count; AdjMatrix gn; gn.vexnum=n; gn.arcnum=Count; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { gn.arcs[i][j].adj=25378; } } for(int i=1;i<=Count;i++) { int u,v,weight; cin>>u>>v>>weight; gn.arcs[u][v].adj=weight; gn.arcs[v][u].adj=weight; } /*for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { cout<<gn.arcs[i][j].adj<<" "; } cout<<endl; }*/ Mintree(gn,1); return 0; }
注释:普利姆算法求最小子树