数据结构第13周 :( 迪杰斯特拉最短路径 + 弗洛伊德求最短路径 + 欧拉回路 + Invitation Cards)

迪杰斯特拉最短路径

【问题描述】

在带权有向图G中,给定一个源点v,求从v到G中的其余各顶点的最短路径问题,叫做单源点的最短路径问题。

在常用的单源点最短路径算法中,迪杰斯特拉算法是最为常用的一种,是一种按照路径长度递增的次序产生最短路径的算法。
在本题中,读入一个有向图的带权邻接矩阵(即数组表示),建立有向图并按照以上描述中的算法求出源点至每一个其它顶点的最短路径长度。

【输入形式】

输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。

以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。

【输出形式】

只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。

请注意行尾输出换行。

【样例输入】

4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0

【样例输出】

6 4 7

【样例说明】

在本题中,需要按照题目描述中的算法完成迪杰斯特拉算法,并在计算最短路径的过程中将每个顶点是否可达记录下来,直到求出每个可达顶点的最短路径之后,算法才能够结束。

迪杰斯特拉算法的特点是按照路径长度递增的顺序,依次添加下一条长度最短的边,从而不断构造出相应顶点的最短路径。

另外需要注意的是,在本题中为了更方便的表示顶点间的不可达状态,可以使用一个十分大的值作为标记。

#include<iostream>
#define N 50
#define Max 99999
using namespace std;

int NodeNum;
int SourceNum;
int R[N][N];
int dist[N];
int path[N];
bool tag[N];

void Dijkstra()
{
    
    
    int i = 0;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        dist[i] = R[SourceNum][i];
        if(i == SourceNum)
        {
    
    
            path[i] = -1;
            tag[i] = false;
        }
        else
        {
    
    
            path[i] = SourceNum;
            tag[i] = true;
        }
    }

    int cnt = NodeNum - 1;
    while(cnt --)
    {
    
    
        int Min = Max;
        int MinId = 0;
        for(i = 0; i < NodeNum; i ++) //找到未访问的最小邻接顶点,并入,将tag置为零
        {
    
    
            if(dist[i] < Min && tag[i] == true)
            {
    
    
                Min = dist[i];
                MinId = i;
            }
        }
        tag[MinId] = false;
        for(i = 0; i < NodeNum; i ++)
        {
    
    
            if(i == MinId || i == SourceNum) continue;
            if(R[MinId][i] + dist[MinId] < dist[i])
            {
    
    
                dist[i] = R[MinId][i] + dist[MinId];
                path[i] = MinId;
            }
        }
    }
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        if(i == SourceNum) continue;
        if(dist[i] == Max) cout<<-1<<" ";
        else
            cout<<dist[i]<<" ";
    }
}

int main()
{
    
    
    cin>>NodeNum>>SourceNum;
    int i, j;
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        for(j = 0; j < NodeNum; j ++)
        {
    
    
            int num;
            cin>>num;
            if(num == 0)
                R[i][j] = Max;
            else
                R[i][j] = num;
        }
    }
    Dijkstra();
    return 0;
}

弗洛伊德求最短路径

【问题描述】

对于下面一张若干个城市,以及城市之间距离的地图,请采用弗洛伊德算法求出所有城市之间的最短路径。
【输入形式】

顶点个数n,以及n*n的邻接矩阵,其中不可达使用9999代替

【输出形式】

每两个顶点之间的最短路径和经过的顶点

注意:顶点自身到自身的dist值为0,path则为该顶点的编号

【样例输入】

4

9999 4 11 9999

6 9999 2 9999

1 9999 9999 1

9999 3 9999 9999

【样例输出】

from 0 to 0: dist = 0 path:0
from 0 to 1: dist = 4 path:0 1
from 0 to 2: dist = 6 path:0 1 2
from 0 to 3: dist = 7 path:0 1 2 3
from 1 to 0: dist = 3 path:1 2 0
from 1 to 1: dist = 0 path:1
from 1 to 2: dist = 2 path:1 2
from 1 to 3: dist = 3 path:1 2 3
from 2 to 0: dist = 1 path:2 0
from 2 to 1: dist = 4 path:2 3 1
from 2 to 2: dist = 0 path:2
from 2 to 3: dist = 1 path:2 3
from 3 to 0: dist = 6 path:3 1 2 0
from 3 to 1: dist = 3 path:3 1
from 3 to 2: dist = 5 path:3 1 2
from 3 to 3: dist = 0 path:3

#include<iostream>
#define N 50
using namespace std;

int dist[N][N];
int path[N][N];
int NodeNum;
void Floyd()
{
    
    
    int i, j, k;
    for(k = 0; k < NodeNum; k ++)
    {
    
    
        for(i = 0; i < NodeNum; i ++)
        {
    
    
            for(j = 0; j < NodeNum; j ++)
            {
    
    
                if(i == j || k == i || k == j) continue;
                if(dist[i][j] > dist[i][k] + dist[k][j])
                {
    
    
                    dist[i][j] = dist[i][k] + dist[k][j];
                    path[i][j] = path[i][k];
                }
            }
        }
    }
    for(i = 0; i < NodeNum; i ++)
    {
    
    
        for(j = 0; j < NodeNum; j ++)
        {
    
    
            cout<<"from "<<i<<" to "<<j<<": dist = ";
            if(dist[i][j] == 9999)
                cout<<0;
            else
                cout<<dist[i][j];
            cout<<" path:";
            int t = path[i][j];
            cout<<i<<" ";
            if(t == j )
            {
    
    
                if(i != j)
                    cout<<j;
            }
            else
            {
    
    
                cout<<path[i][j]<<" ";
                while(t != j)
                {
    
    
                    cout<<path[t][j]<<" ";
                    t = path[t][j];
                }
            }

            cout<<endl;
        }
    }
}

int main()
{
    
    
    cin>>NodeNum;
    int i, j;
    for(i = 0; i <NodeNum; i ++)
    {
    
    
        for(j = 0; j <NodeNum; j ++)
        {
    
    
            cin>>dist[i][j];
            path[i][j] = j;
        }
    }
    Floyd();
    return 0;
}

欧拉回路

【问题描述】

欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?

【输入形式】

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结束。

【输出形式】

每个测试用例的输出占一行,若欧拉回路存在则输出1,否则输出0。

【样例输入】

3 3

1 2

1 3

2 3

3 2

1 2

2 3

0

【样例输出】

1

0

【备注】

此题是浙大计算机研究生复试上机考试-2008年真题。

#include<iostream>
using namespace std;
int main()
{
    
    
    while(1)
    {
    
    
        int NodeNum;
        int RelationNum;
        cin>>NodeNum;
        if(NodeNum == 0) break;
        cin>>RelationNum;
        int In[NodeNum];
        while(RelationNum --)
        {
    
    
            int n1;
            int n2;
            cin>>n1>>n2;
            In[n1 - 1] ++;
            In[n2 - 1] ++;
        }
        int flag = 1;
        int i = 0;
        for(i = 0; i < NodeNum; i ++)
        {
    
    
            if(In[i] % 2 != 0) flag = 0;
        }
        if(flag) cout<<1<<endl;
        else cout<<0<<endl;
    }
    return 0;
}

Invitation Cards

【Problem Description】

In the age of television, not many people attend theater performances. Antique Comedians of Malidinesia are aware of this fact. They want to propagate theater and, most of all, Antique Comedies. They have printed invitation cards with all the necessary information and with the programme. A lot of students were hired to distribute these invitations among the people. Each student volunteer has assigned exactly one bus stop and he or she stays there the whole day and gives invitation to people travelling by bus. A special course was taken where students learned how to influence people and what is the difference between influencing and robbery.

The transport system is very special: all lines are unidirectional and connect exactly two stops. Buses leave the originating stop with passangers each half an hour. After reaching the destination stop they return empty to the originating stop, where they wait until the next full half an hour, e.g. X:00 or X:30, where ‘X’ denotes the hour. The fee for transport between two stops is given by special tables and is payable on the spot. The lines are planned in such a way, that each round trip (i.e. a journey starting and finishing at the same stop) passes through a Central Checkpoint Stop (CCS) where each passenger has to pass a thorough check including body scan.

All the ACM student members leave the CCS each morning. Each volunteer is to move to one predetermined stop to invite passengers. There are as many volunteers as stops. At the end of the day, all students travel back to CCS. You are to write a computer program that helps ACM to minimize the amount of money to pay every day for the transport of their employees.

【Input】

The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case begins with a line containing exactly two integers P and Q, 1 <= P,Q <= 1000000. P is the number of stops including CCS and Q the number of bus lines. Then there are Q lines, each describing one bus line. Each of the lines contains exactly three numbers - the originating stop, the destination stop and the price. The CCS is designated by number 1. Prices are positive integers the sum of which is smaller than 1000000000. You can also assume it is always possible to get from any stop to any other stop.

【Output】

For each case, print one line containing the minimum amount of money to be paid each day by ACM for the travel costs of its volunteers.

【Sample Input】

2

2 2

1 2 13

2 1 33

4 6

1 2 10

2 1 60

1 3 20

3 4 10

2 4 5

4 1 50

【Sample Output】

46

210

#include<iostream>
#define N 50
#define Max 99999
using namespace std;

int dist[N][N];

void MinCost(int limit) //limit可取
{
    
    
    int i, j, k; //通过弗洛伊德的三重循环计算出每两个顶点间的最短距离
    for(k = 1; k <= limit; k ++)
    {
    
    
        for(i = 1; i <= limit; i ++)
        {
    
    
            for(j = 1; j <= limit; j ++)
            {
    
    
                if(i == j || k == i || k == j)continue;
                if(dist[i][k] + dist[k][j] < dist[i][j])
                {
    
    
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    int res = 0;
    for(j = 2; j <= limit; j ++)
    {
    
    
        res += dist[1][j];
        res += dist[j][1];
    }
    cout<<res<<endl;
}

int main()
{
    
    
    int cnt = 0;
    cin>>cnt;
    while(cnt --)
    {
    
    
        int NodeNum;
        int RelationNum;
        cin>>NodeNum>>RelationNum;
        int i, j;
        for(i = 0; i < N; i ++)
        {
    
    
            for(j = 0; j < N; j ++)
            {
    
    
                dist[i][j] = Max;
            }
        }
        while(RelationNum --)
        {
    
    
            int n1;
            int n2;
            int w;
            cin>>n1>>n2>>w;
            dist[n1][n2] = w; //从下标一号开始
        }
        MinCost(NodeNum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_51800570/article/details/129178858