中国大学MOOC ZJU-数据结构-图(上)

(其实这些都是DFS,BFS的应用,理解了问题都应该很好解决的。)

06-图1 列出连通集 (25分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:
按照"{ v​1 v​2​​ … v​k }"的格式,每行输出一个连通集。先输出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 }

其实就是BFS DFS的简单应用。
DFS借助递归实现,BFS借助队列实现。
连通集就是连在一块就行了,不需要一定形成环。

#include<cstdio>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cstring>
using namespace std;

int graph[11][11] = {0};
bool visited[12] = {0};
int n,e;
queue<int> q;

void DFS(int v)
{
    if(visited[v])
        return;
    else{
        visited[v] = true;
        printf("%d ",v);
        for(int i = 0; i < n; i++){
            if(!visited[i] && graph[v][i])
                DFS(i);
        }
    }
}

void BFS(int v)
{
    if(visited[v])
        return;
    visited[v] = true;
    printf("%d ",v);
    for(int i = 0; i < n; i++){
        if(!visited[i] && graph[v][i])
            q.push(i);
    }
    while(!q.empty()){
        int temp = q.front();
        q.pop();
        BFS(temp);
    }
}

int main(void)
{
    scanf("%d%d",&n,&e);
    for(int i = 0; i < e; i++){
        int v1 = 0,v2 = 0;
        scanf("%d%d",&v1,&v2);
        graph[v1][v2] = graph[v2][v1] = 1;
    }
    for(int i = 0; i < n; i++){
        if(!visited[i]){
            printf("{ ");
            DFS(i);
            printf("}\n");
        }
    }
    memset(visited,0,sizeof(visited));
    for(int i = 0; i < n; i++){
        if(!visited[i]){
            printf("{ ");
            BFS(i);
            printf("}\n");
        }
    }
    return 0;
}

06-图2 Saving James Bond - Easy Version (25分)

This time let us consider the situation in the movie “Live and Let Die” in which James Bond, the world’s most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape – he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head… Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).

Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.

Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.

Output Specification:
For each test case, print in a line “Yes” if James can escape, or “No” if not.

Sample Input 1:
14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20

-13 29
-30 15
-35 40
12 12

Sample Output 1:
Yes

Sample Input 2:
4 13
-12 12
12 12
-12 -12
12 -12

Sample Output 2:
No

#include<cstdio>
#include<cmath>
#include<cstring>

struct node
{
    double x;
    double y;
}a[105];
bool visit[105] = {0};
int n,d;

double get_distance(node a,node b)//求两点间距离
{
    double x = (a.x-b.x)*(a.x-b.x);
    double y = (a.y-b.y)*(a.y-b.y);
    return sqrt(x+y);
}

bool DFS(node cur)
{
    if(cur.x+d>=50 || cur.x-d <= -50 || cur.y+d >= 50 || cur.y-d <= -50)
        return true; //到岸边了
    for(int i = 1;i <= n; i++){
        if(!visit[i] && get_distance(a[i],cur) <= d){
            visit[i] = true;
            if(!DFS(a[i]))
                continue;
            else
                return true;
        }
    }
    return false;
}

int main(void)
{
    bool flag = false;
    scanf("%d%d",&n,&d);
    memset(visit,0,sizeof(visit));
    a[0].x = a[0].y = 0.0;
    for(int i = 1; i <= n; i++)
        scanf("%lf%lf",&a[i].x,&a[i].y);
    for(int i = 1; i <= n; i++){
        if(!visit[i] && get_distance(a[0],a[i]) <= 7.5+d)//注意了!!diameter是直径不是半径!!!!
            flag = DFS(a[i]);
        if(flag){
            printf("Yes\n");
            return 0;
        }
    }
    printf("No\n");
    return 0;
}

06-图3 六度空间 (30分)

“六度空间”理论又称作“六度分隔(Six Degrees of Separation)”理论。这个理论可以通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过五个人你就能够认识任何一个陌生人。”如图1所示。

在这里插入图片描述
图1 六度空间示意图
“六度空间”理论虽然得到广泛的认同,并且正在得到越来越多的应用。但是数十年来,试图验证这个理论始终是许多社会学家努力追求的目标。然而由于历史的原因,这样的研究具有太大的局限性和困难。随着当代人的联络主要依赖于电话、短信、微信以及因特网上即时通信等工具,能够体现社交网络关系的一手数据已经逐渐使得“六度空间”理论的验证成为可能。

假如给你一个社交网络图,请你对每个节点计算符合“六度空间”理论的结点占结点总数的百分比。

输入格式:
输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤10
​3
​​ ,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。

输出格式:
对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。

输入样例:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10

输出样例:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%

这题用DFS最后一个数据点会TLE!只能用BFS解决。
用BFS一层一层往外拓展,拓展到第六层就可以了。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;

int node[1005][1005] = {0};
int num[1005] = {0};
int visit[1005] = {0};
int dis = 0;
int n,m;
queue<int> q;

int BFS(int v)
{
    int count = 1,level = 0;
    int last = v,tail = 0;//在下一层都入列后,将下一层的终点记成tail,last是正在遍历的层的最后一个结点
    q.push(v);
    visit[v] = 1;
    while(!q.empty()){//把该层结点都弹出寻找与此连接的下一层结点
        v = q.front();
        q.pop();
        for(int i = 1; i <= n; i++){
            if(!visit[i] && node[v][i]){
                visit[i] = 1;
                q.push(i);
                tail = i;
                count++;
            }
        }
        if(v == last){//说明这一层的结点弹出完毕,进入到下一层,下一层的最后一个结点就是tail
            level++;
            last = tail;
        }
        if(level == 6)
            break;
    }
    return count;
}

int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        node[a][b] = node[b][a] = 1;
    }
    for(int i = 1; i <= n; i++){
        memset(visit,0,sizeof(visit));
        while(!q.empty())
            q.pop();
        num[i] = BFS(i);
    }
    for(int i = 1;i <= n; i++){
        printf("%d: %.2lf%\n",i,double(num[i])/double(n)*100.0);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值