1. | 哈夫曼编码 【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。 【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd...的默认顺序给出。然后是某字符串和某01序列。 【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。 【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。 【样例输入】 8 aabchg 00011110111111001 【样例输出】 0001 000100011011100010000 acdef |
---|
#include <bits/stdc++.h>
using namespace std;
typedef char** HuffmanCode;
typedef struct
{
int weight;
int parent;
int LChild;
int RChild;
}HTNode, HuffmanTree[10001];
void select(HuffmanTree ht, int n, int &s1, int &s2)
{
int min, _min;//min是最小值,_min是第二小的值,分别赋给左,右子树
for (int i = 1; i <= n ;i++)
{
if (ht[i].parent == 0) {
min = i; break;
}
}
for (int i = min+1; i <= n; i++)
{
if (ht[i].weight < ht[min].weight && ht[i].parent == 0) {
min = i;
}
}
s1 = min;
for (int i = 1; i <= n; i++)
{
if (ht[i].parent == 0 && i != s1) {
_min = i;
break;
}
}
for (int i = _min + 1; i <= n; i++)
{
if (ht[i].weight < ht[_min].weight && i != s1 && ht[i].parent == 0) {
_min = i;
}
}
s2 = _min;
}
void CreHuffmanTree(HuffmanTree &ht, int w[], int n)
{
for (int i = 1; i <= n; i++) ht[i] = { w[i],0,0,0 };
int m = 2 * n - 1;
for (int i = n + 1; i <= m; i++) ht[i] = { 0,0,0,0 };
for (int i = n + 1; i <= m ; i++)
{
int s1, s2;
select(ht, i - 1, s1, s2);
ht[i].weight = ht[s1].weight + ht[s2].weight;
ht[s1].parent = ht[s2].parent = i;
ht[i].LChild = s1, ht[i].RChild = s2;
}
}
void CreHuffmanCode(HuffmanTree &ht, HuffmanCode &hc, int n)
{
hc = (char**)malloc(sizeof(char*) * n + 1);
char* code = (char*)malloc(sizeof(char) * n);
code[n - 1] = '\0';
for (int i = 1; i <= n; i++)
{
int start = n - 1;
int c = i;
int p = ht[i].parent;
while (p)
{
if (ht[p].LChild == c) code[--start] = '0';
else code[--start] = '1';
c = p;
p = ht[c].parent;
}
hc[i] = (char*)malloc((n - start) * sizeof(char));
strcpy(hc[i], &code[start]);
}
free(code);
}
void code(HuffmanTree ht, int n, string s)
{
int i = 0;
while (i<(signed)s.size())
{
int cur = 2 * n - 1;
while (ht[cur].LChild != 0 && ht[cur].RChild != 0)
{
if (s[i] == '0') {
cur = ht[cur].LChild;
}
else if (s[i] == '1') {
cur = ht[cur].RChild;
}
i++;
}
char ch = 'a' + cur - 1;
cout << ch;
}
}
int main()
{
int n, w[10001];
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
HuffmanTree ht;
CreHuffmanTree(ht, w, n);
HuffmanCode hc;
CreHuffmanCode(ht, hc, n);
for (int i = 1; i <= n; i++)
{
cout << hc[i] << endl;
}
string sample;
cin >> sample;
for (int i = 0; i < sample.size(); i++)
{
int temp = sample[i] - 96;
cout << hc[temp];
}
cout << endl;
string s;
cin >> s;
code(ht, n, s);
}
2. | 带权路径长度 【问题描述】 输入一串正整数,正整数之间用空格键分开,请建立一棵哈夫曼树,以输入的数字作为叶子节点,求这棵哈夫曼树的带权路径长度。 【输入形式】 首先输入正整数的个数n,然后是对应的n个正整数,正整数个数不超过10个 【输出形式】 输出创建的哈夫曼树的带权路径总长度 【样例输入】 5 4 5 6 7 8 【样例输出】 69 |
---|
#include<iostream>
using namespace std;
typedef struct node
{
int weight;
int l,r,parent;
}huff;
void select(huff a[],int n,int &q1,int &q2)
{
for(int i=0;i<n;i++)
{
if(a[i].parent==0)
{
q1=i;break;
}
}
for(int i=0;i<n;i++)
{
if(a[i].parent==0 && a[i].weight<a[q1].weight)
q1=i;
}
for(int i=0;i<n;i++)
{
if(a[i].parent==0 && i!=q1)
{
q2=i;break;
}
}
for(int i=0;i<n;i++)
{
if(a[i].weight<a[q2].weight && a[i].parent==0 &&i!=q1)
{
q2=i;
}
}
}
void creat(int n,huff a[])
{
for(int i=0;i<n;i++)
{
cin >> a[i].weight;
a[i].parent=a[i].l=a[i].r=0;
}
for(int i=0;i<=(2*n-1);i++)
{
a[i].parent=a[i].l=a[i].r=0;
}
int q1,q2;
for(int i=n;i<(2*n-1);i++)
{
select(a,i,q1,q2);
a[q1].parent=i;
a[q2].parent=i;
a[i].l=q1;
a[i].r=q2;
a[i].weight=a[q1].weight+a[q2].weight;
}
}
int gethuff(huff a[],int n)
{
int num,sum=0;
for(int i=0;i<n;i++)
{
num=0;
int s=i;
while(a[s].parent!=0)
{
s=a[s].parent;
num++;
}
sum += num*a[i].weight;
}
return sum;
}
int main()
{
int n;
cin >> n;
huff a[100];
creat(n,a);
cout << gethuff(a,n);
return 0;
}
3. | 图的遍历及连通性 【问题描述】 |
---|
#include<iostream>
#include<queue>
using namespace std;
typedef struct graph
{
int vertexs;
int arcs[100][100];
}graph;
int visited[100]={0};//遍历的邻接点,被访问为1,未被访问为0
void creat(graph &g)
{
int i,j;
cin >> g.vertexs;//总数
for(i=0;i<g.vertexs;i++)
{
for(j=0;j<g.vertexs;j++)
{
cin >> g.arcs[i][j];
}
}
}
void bfs(graph g,int v)
{
visited[v]=1;
queue<int> q;
q.push(v);
while(!q.empty())
{
v=q.front();
q.pop();
for(int i=0;i<g.vertexs;i++)//遍历列j
{
if(g.arcs[v][i]!=0 && visited[i]!=1)
bfs(g,i);
}
}
}
int main()
{
graph g;
int i,sum=0;
creat(g);
for(i=0;i<g.vertexs;i++)
{
if(visited[i]!=1)
{
bfs(g,i);//遍历行i
sum++;
}
}
cout << sum <<endl;
return 0;
}
4. | 犯罪团伙 【题目描述】 此题必须采用邻接表的存储结构,建立图的存储,然后采用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>
using namespace std;
int visited[100]={0};//判断是否被访问,是1,否0
typedef struct arcnode//边表
{
int adjvex;
struct arcnode*nextarc;
}arcnode;
typedef struct vertexnode//顶点表
{
int data;
arcnode*firstarc;
} vertexnode;
typedef struct //邻接表
{
vertexnode vertex[100];
int vexnum,arcnum;
} adjlist;
void creat(adjlist &g)
{
cin >> g.vexnum >>g.arcnum;
int x,y,i;
for(i=0;i<g.vexnum;i++)
{
g.vertex[i].firstarc=NULL;
}
for(i=0;i<g.arcnum;i++)
{
cin >> x >>y;
arcnode*p1;
p1=new arcnode;
p1->adjvex=y;
p1->nextarc=g.vertex[x].firstarc;
g.vertex[x].firstarc=p1;
arcnode*p2;
p2=new arcnode;
p2->adjvex=x;
p2->nextarc=g.vertex[y].firstarc;
g.vertex[y].firstarc=p2;
}
}
void DFS(adjlist &g,int v)
{
int j;
visited[v]=1;
arcnode*p=g.vertex[v].firstarc;
while(p)
{
j=p->adjvex;
if(visited[j]==0)
{
DFS(g,j);
}
p=p->nextarc;
}
}
int main()
{
adjlist g;
creat(g);
int i,sum=0;
for(i=0;i<g.vexnum;i++)
{
if(visited[i]!=1)
{
DFS(g,i);
sum++;
}
}
cout << sum <<endl;
return 0;
}
5. | 图形窗口问题 【问题描述】 在某图形操作系统中,有N个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域。窗口的边界上的点也属于该窗口。窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的内容。 当你点击屏幕上一个点的时候,你就选择了处于被点击位置的最顶层窗口,并且这个窗口就会被移到所有窗口的最顶层,而剩余的窗口的层次顺序不变。如果你点击的位置不属于任何窗口,则系统会忽略你这次点击。 现在我们希望你写一个程序模拟点击窗口的过程。 【输入形式】 输入的第一行有两个正整数,即N和M。(1<=N<=10,1<=M<=10)接下来N行按照从最下层到最顶层的顺序给出N个窗口的位置。每行包含四个非负整数x1,y1,x2,y2,表示该窗口的一对顶点坐标分别为(x1,y1)和(x2,y2)。保证x1<x2,y1<y2。 接下来M行每行包含两个非负整数x,y,表示一次鼠标点击的坐标。题目中涉及到的所有点和矩形的顶点的x,y坐标分别不超过2559和1439。 【输出形式】 输出包括M行,每一行表示一次鼠标点击的结果。如果该次鼠标点击选择了一个窗口,则输出这个窗口的编号(窗口按照输入中的顺序从1编号到N);如果没有,则输出"IGNORED"(不含双引号)。 【样例输入】 3 4 0 0 4 4 1 1 5 5 2 2 6 6 1 1 0 0 4 4 0 5 【样例输出】 2 1 1 IGNORED 【样例说明】 第一次点击的位置同时属于第1和第2个窗口,但是由于第2个窗口在上面,它被选择并且被置于顶层。 第二次点击的位置只属于第1个窗口,因此该次点击选择了此窗口并将其置于顶层。现在的三个窗口的层次关系与初始状态恰好相反了。第三次点击的位置同时属于三个窗口的范围,但是由于现在第1个窗口处于顶层,它被选择。 最后点击的(0,5)不属于任何窗口。 |
---|
#include<iostream>
using namespace std;
struct window//储存一个窗口的坐标
{
int wx1,wx2;
int wy1,wy2;
int num;
} ;
struct click//储存一次鼠标点击的结果
{
int x,y;
};
int main()
{
int M,N;
cin >> M >> N;
window w[M+N];
click c[N];
int temp=0;
//cout << M <<N;
for(int i=0;i<M;i++)
{
cin >> w[i].wx1 >>w[i].wy1>>w[i].wx2>>w[i].wy2;
w[i].num = i+1;
}
for(int i=0;i<N;i++)
{
cin >> c[i].x>>c[i].y;
int flag=0,j;
for(j=M+temp-1;j>=0;j--)
{
if(c[i].x<=w[j].wx2&&c[i].x>=w[j].wx1&&
c[i].y<=w[j].wy2&&c[i].y>=w[j].wy1)
{
cout << w[j].num <<endl;
flag=1;
temp++;
w[M+temp-1]=w[j];//被点击窗口置于顶层
break;
}
}
if(flag==0)
cout << "IGNORED"<<endl;
}
}