图的遍历及连通性
【问题描述】
根据输入的图的邻接矩阵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>
#define N 100
#include<queue>
using namespace std;
int matrix[N][N];
void bfs(int node, int matrix[N][N], int visited[N], int limit)
{
queue<int> s;
s.push(node);
visited[node] = 1;
while(!s.empty())
{
node = s.front();
s.pop();
int j = 0;
for(j = 1; j < limit; j ++)
{
if(matrix[node][j] == 1 && visited[j] == 0)
{
s.push(j);
visited[j] = 1;
}
}
}
}
int main()
{
int node;
cin>>node;
int i = 0;
int j = 0;
for(i = 1; i < node + 1; i ++) //创建邻接矩阵,从一号位开始存放
{
for(j = 1; j < node + 1; j++)
cin>>matrix[i][j];
}
int res = 0;
int visited[node + 1];
for(i = 0; i < node + 1; i ++) visited[i] = 0;//初始化访问数组
for(i = 1; i < node + 1; i ++)
{
if(visited[i] == 0)
{
bfs(i, &matrix[0], visited, node + 1); //二维数组传第一行的地址
res ++;
}
}
cout<<res;
return 0;
}
犯罪团伙
【题目描述】
此题必须采用邻接表的存储结构,建立图的存储,然后采用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>
#define N 50
using namespace std;
int matrix[N][N];
void dfs(int human, int visited[N], int limit)
{
visited[human] = 1;
int j = 1;
for(; j < limit; j ++)
{
if(matrix[human][j] == 1 && visited[j] == 0)
dfs(j, visited, limit);
}
}
int main()
{
int human; //罪犯数量
int relation; // 关系数量
cin>>human>>relation;
int i = 0;
int j = 0;
for(i = 0; i < N; i ++)
{
for(j = 0; j < N; j ++)
matrix[i][j] = 0;
}
while(relation --)
{
int i, j;
cin>>i>>j;
matrix[i][j] = 1;
matrix[j][i] = 1;
}
int visited[human + 1];
for(i = 0; i < human + 1; i ++) visited[i] = 0;
int res = 0;
for(i = 1; i < human + 1; i++)
{
if(visited[i] == 0)
{
dfs(i, visited, human + 1);
res ++;
}
}
cout<<res;
return 0;
}
图形窗口问题
【问题描述】
在某图形操作系统中,有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)不属于任何窗口。
【备注】2014年3月CCF-CSP考试真题第2题
#include<iostream>
#define N 20
using namespace std;
typedef struct
{
int x;
int y;
}point;
typedef struct
{
point p1;
point p2;
int num;
}windows;
int main()
{
windows w[N];
int WindowsNum = 0;
cin>>WindowsNum;
int ClickNum = 0;
cin>>ClickNum;
int i = 1;
while(1)
{
int x1, y1, x2, y2;
cin>>x1>>y1>>x2>>y2;
point a, b;
a.x = x1;
a.y = y1;
b.x = x2;
b.y = y2;
windows p;
p.p1 = a;
p.p2 = b;
p.num = i;
w[i] = p;
if(i == WindowsNum) break;
i ++;
}
while(ClickNum --)
{
int x, y;
cin>>x>>y;
int pos = 0;
for(pos = WindowsNum; pos > 0; pos --)
{
if(x >= w[pos].p1.x && y >= w[pos].p1.y && x <= w[pos].p2.x && y <= w[pos].p2.y)
{
cout<<w[pos].num<<endl;
int i = 0;
windows temp = w[pos];
for(i = pos; i < WindowsNum; i ++)
{
w[i] = w[i + 1];
}
w[WindowsNum] = temp;
break;
}
}
if(pos == 0) cout<<"IGNORED"<<endl;
}
return 0;
}
最小生成树的权值之和
【问题描述】
已知含有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>
#define N 50
#define Max 999999
using namespace std;
int R[N][N];
typedef struct
{
int adjvex;
int loweight;
int flag;
}Closedge;
int Min(Closedge * MTree, int limit)
{
int min = 99999;
int i = 0;
int res = 0;
for(i = 1; i <= limit; i ++)
{
if(MTree[i].loweight < min && MTree[i].flag == 1)
{
min = MTree[i].loweight;
res = i;
}
}
return res;
}
void Prim(int limit)
{
int sum = 0;
Closedge MTree[limit + 1];
int i = 0;
for(i = 1; i <= limit; i ++) //初始化
{
if(i != 1)
MTree[i].adjvex = 1;
MTree[i].flag = 1;
MTree[i].loweight = R[1][i];
}
for(i = 2; i <= limit; i ++)
{
int MinId = Min(MTree, limit);
cout<<MTree[MinId].adjvex<<'-'<<MinId<<':'<<MTree[MinId].loweight<<endl;
sum += MTree[MinId].loweight;
MTree[MinId].flag = 0;
int j = 0;
for(j = 2; j <= limit; j ++)
{
if(R[MinId][j] < MTree[j].loweight)
{
MTree[j].loweight = R[MinId][j];
MTree[j].adjvex = MinId;
}
}
}
cout<<sum;
}
int main()
{
int NodeNum;
int RelationNum;
cin>>NodeNum>>RelationNum;
int i = 0;
int j = 0;
for(i = 1; i <= NodeNum; i++)
{
for(j = 1; j <= NodeNum; j ++)
{
R[i][j] = Max;
}
}
while(RelationNum --)
{
int i, j, k;
cin>>i>>j>>k;
R[i][j] = k;
R[j][i] = k;
}
Prim(NodeNum);
return 0;
}
Jungle Roads
请用kruskal算法编程实现下面的问题。
The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to maintain. The Council of Elders must choose to stop maintaining some roads. The map above on the left shows all the roads in use now and the cost in aacms per month to maintain them. Of course there needs to be some way to get between all the villages on maintained roads, even if the route is not as short as before. The Chief Elder would like to tell the Council of Elders what would be the smallest amount they could spend in aacms per month to maintain roads that would connect all the villages. The villages are labeled A through I in the maps above. The map on the right shows the roads that could be maintained most cheaply, for 216 aacms per month. Your task is to write a program that will solve such problems.
Input
The input consists of one to 100 data sets, followed by a final line containing only 0. Each data set starts with a line containing only a number n, which is the number of villages, 1 < n < 27, and the villages are labeled with the first n letters of the alphabet, capitalized. Each data set is completed with n-1 lines that start with village labels in alphabetical order. There is no line for the last village. Each line for a village starts with the village label followed by a number, k, of roads from this village to villages with labels later in the alphabet. If k is greater than 0, the line continues with data for each of the k roads. The data for each road is the village label for the other end of the road followed by the monthly maintenance cost in aacms for the road. Maintenance costs will be positive integers less than 100. All data fields in the row are separated by single blanks. The road network will always allow travel between all the villages. The network will never have more than 75 roads. No village will have more than 15 roads going to other villages (before or after in the alphabet). In the sample input below, the first data set goes with the map above.
Output
The output is one integer per line for each data set: the minimum cost in aacms per month to maintain a road system that connect all the villages. Caution: A brute force solution that examines every possible set of roads will not finish within the one minute time limit.
#include<iostream>
#define N 100
using namespace std;
typedef struct
{
char node1;
char node2;
int weight;
}MTree;
int parent[N];
void Init(int limit)
{
int i;
for(i = 0; i <= limit; i ++)
{
parent[i] = i;
}
}
int find(char a)
{
int m = int(a) - 65;
int root = int(a) - 65;
while(root != parent[root]) root = parent[root];
while(m != root)
{
int t = parent[m];
parent[m] = root;
m = t;
}
return root;
}
void unite(char a, char b)
{
int m = find(a);
int n = find(b);
parent[n] = m;
}
void Sort(MTree tree[N], int limit)
{
int i, j;
for(i = 0; i <= limit; i ++)
{
int min = tree[i].weight;
int minid = i;
for(j = i + 1; j <= limit; j ++)
{
if(tree[j].weight < min)
{
min = tree[j].weight;
minid = j;
}
}
if(minid != i)
{
MTree temp = tree[i];
tree[i] = tree[minid];
tree[minid] = temp;
}
}
}
void Kruskal(MTree tree[N], int limit)
{
int res = 0;
int i = 0;
for(i = 0; i <= limit; i ++)
{
if(find(tree[i].node1) != find(tree[i].node2))
{
unite(tree[i].node1, tree[i].node2);
res += tree[i].weight;
//cout<<tree[i].weight<<endl;
}
}
cout<<res<<endl;
}
int main()
{
MTree tree[N];
int NodeNum;
cin>>NodeNum;
int i = 1;
int count = -1;
while(1)
{
char a1;
cin>>a1;
int RelationNum;
cin>>RelationNum;
while(RelationNum --)
{
count ++;
char a2;
cin>>a2;
int r;
cin>>r;
tree[count].node1 = a1;
tree[count].node2 = a2;
tree[count].weight = r;
}
if(i == NodeNum - 1) break;
i ++;
}
Init(count);
Sort(tree, count);
/*for(i = 0; i <= count; i ++)
{
cout<<tree[i].node1<<" "<<tree[i].node2<<" "<<tree[i].weight<<endl;
}
cout<<endl;*/
Kruskal(tree, count);
return 0;
}