Semaine 13 des structures de données : (Chemin le plus court de Dijkstra + Chemin le plus court de Floyd + Circuit d'Euler + Cartes d'invitation)

Chemin le plus court de Dijkstra

【Description du problème】

Dans le graphe orienté pondéré G , étant donné un point source v , le problème de trouver le chemin le plus court de v au reste des sommets de G est appelé le problème du chemin le plus court d'un seul point source.

Parmi les algorithmes de chemin le plus court à source unique couramment utilisés, l'algorithme de Dijkstra est le plus couramment utilisé, qui est un algorithme qui génère le chemin le plus court dans l'ordre d'augmentation de la longueur du chemin.
Dans cette question, lisez dans une matrice de contiguïté pondérée (c'est-à-dire une représentation matricielle) d'un graphe orienté, construisez un graphe orienté et trouvez la longueur de chemin la plus courte du point source à l'autre sommet selon l'algorithme décrit ci-dessus.

【Formulaire de saisie】

La première ligne d'entrée contient 2 entiers positifs n et s, indiquant qu'il y a n sommets dans le graphe, et le point source est s. Où n ne dépasse pas 50 et s est inférieur à n.

Chacune des n lignes suivantes a n entiers séparés par des espaces. Pour le jième entier de la iième ligne, s'il est supérieur à 0, cela signifie que le iième sommet a une arête dirigée pointant vers le jième sommet, et le poids est la valeur entière correspondante ; si cet entier est 0, cela signifie qu'il n'y a pas de i Une arête dirigée pointant vers j. Lorsque i et j sont égaux, l'entier correspondant est garanti égal à 0.

【Format de sortie】

Il n'y a qu'une seule ligne, avec un total de n-1 entiers, indiquant la longueur du chemin le plus court entre le point source et chaque autre sommet. S'il n'y a pas de chemin entre la source et le sommet correspondant, affiche -1.

Notez la sortie de nouvelle ligne à la fin de la ligne.

【Echantillon d'entrée】

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

【Échantillon de sortie】

6 4 7

【Exemple descriptif】

Dans cette question, il est nécessaire de compléter l'algorithme de Dijkstra selon l'algorithme dans la description du titre, et d'enregistrer si chaque sommet est accessible lors du calcul du chemin le plus court, jusqu'à ce que le chemin le plus court de chaque sommet accessible soit obtenu, L'algorithme peut se terminer .

La caractéristique de l'algorithme de Dijkstra est d'ajouter l'arête la plus courte suivante dans l'ordre de longueur de chemin croissante, de manière à construire en continu le chemin le plus court des sommets correspondants.

De plus, il convient de noter que dans cette question, afin d'indiquer plus commodément l'état inaccessible entre les sommets, une très grande valeur peut être utilisée comme marque.

#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;
}

Le chemin le plus court de Freud

【Description du problème】

Pour la carte suivante de plusieurs villes et la distance entre les villes, veuillez utiliser l'algorithme de Floyd pour trouver le chemin le plus court entre toutes les villes.
【Formulaire de saisie】

Le nombre de sommets n et la matrice d'adjacence de n*n, qui est inaccessible, utilisent 9999 à la place

【Format de sortie】

Le chemin le plus court entre tous les deux sommets et les sommets passés

Remarque : la valeur dist du sommet lui-même à lui-même est 0, et le chemin est le numéro du sommet

【Echantillon d'entrée】

4

9999 4 11 9999

6 9999 2 9999

1 9999 9999 1

9999 3 9999 9999

【Échantillon de sortie】

de 0 à 0 : dist = 0 chemin : 0
de 0 à 1 : dist = 4 chemin : 0 1
de 0 à 2 : dist = 6 chemin : 0 1 2
de 0 à 3 : dist = 7 chemin : 0 1 2 3
de 1 à 0 : dist = 3 chemin : 1 2 0
de 1 à 1 : dist = 0 chemin : 1
de 1 à 2 : dist = 2 chemin : 1 2
de 1 à 3 : dist = 3 chemin : 1 2 3
de 2 à 0 : dist = 1 chemin : 2 0
de 2 à 1 : dist = 4 chemin : 2 3 1
de 2 à 2 : dist = 0 chemin : 2
de 2 à 3 : dist = 1 chemin : 2 3
de 3 à 0 : dist = 6 chemin : 3 1 2 0
de 3 à 1 : dist = 3 chemin : 3 1
de 3 à 2 : dist = 5 chemin : 3 1 2
de 3 à 3 : dist = 0 chemin : 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;
}

Circuit d'Euler

【Description du problème】

Un circuit d'Euler fait référence à un circuit qui ne peut être tracé qu'une seule fois sur chaque arête du graphique sans laisser le stylo quitter le papier, et peut revenir au point de départ. Etant donné un graphe, existe-t-il un circuit d'Euler ?

【Formulaire de saisie】

L'entrée de test se compose de plusieurs cas de test. La première ligne de chaque cas de test donne deux entiers positifs, qui sont le nombre de nœuds N ( 1 < N < 1000 ) et le nombre d'arêtes M ; les M lignes suivantes correspondent à M arêtes, et chaque ligne donne une paire d'arêtes positives. entiers, sont les numéros des deux nœuds directement reliés par l'arête (les nœuds sont numérotés de 1 à N). L'entrée se termine lorsque N vaut 0.

【Format de sortie】

La sortie de chaque cas de test occupe une ligne, si le circuit d'Euler existe, il sort 1, sinon il sort 0.

【Echantillon d'entrée】

3 3

1 2

1 3

2 3

3 2

1 2

2 3

0

【Échantillon de sortie】

1

0

【Remarque】

Cette question est la vraie question de l'examen informatisé de réexamen des diplômés en informatique de l'Université du Zhejiang-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;
}

Cartes d'invitation

【Description du problème】

À l'ère de la télévision, peu de gens assistent à des représentations théâtrales. Les comédiens antiques de Malidinesia sont conscients de ce fait. Ils veulent propager le théâtre et surtout les comédies antiques. Ils ont imprimé des cartes d'invitation avec toutes les informations nécessaires et avec le programme. Beaucoup d'étudiants ont été embauchés pour distribuer ces invitations parmi les gens. Chaque étudiant volontaire a assigné exactement un arrêt de bus et il y reste toute la journée et invite les personnes qui voyagent en bus. Un cours spécial a été suivi où les étudiants ont appris comment influencer les gens et quelle est la différence entre influencer et voler.

Le système de transport est très particulier : toutes les lignes sont unidirectionnelles et relient exactement deux arrêts. Les bus partent de l'arrêt d'origine avec des passagers toutes les demi-heures. Après avoir atteint l'arrêt de destination, ils retournent vides à l'arrêt d'origine, où ils attendent jusqu'à la prochaine demi-heure pleine, par exemple X:00 ou X:30, où « X » désigne l'heure. La redevance pour le transport entre deux arrêts est donnée par des tableaux spéciaux et est payable sur place. Les lignes sont planifiées de telle sorte que chaque aller-retour (c'est-à-dire un voyage commençant et finissant au même arrêt) passe par un point de contrôle central (CCS) où chaque passager doit passer un contrôle approfondi comprenant un scanner corporel.

Tous les étudiants membres de l'ACM quittent le CCS chaque matin. Chaque bénévole doit se rendre à un arrêt prédéterminé pour inviter des passagers. Il y a autant de bénévoles que d'arrêts. À la fin de la journée, tous les étudiants retournent au CCS. Vous devez écrire un programme informatique qui aide ACM à minimiser le montant d'argent à payer chaque jour pour le transport de ses employés.

【Saisir】

L'entrée se compose de N cas. La première ligne de l'entrée ne contient que l'entier positif N. Suivez ensuite les cas. Chaque cas commence par une ligne contenant exactement deux entiers P et Q, 1 <= P,Q <= 1000000. P est le nombre d'arrêts incluant CCS et Q le nombre de lignes de bus. Ensuite, il y a les lignes Q, chacune décrivant une ligne de bus. Chacune des lignes contient exactement trois numéros - l'arrêt de départ, l'arrêt de destination et le prix. Le CCS est désigné par le chiffre 1. Les prix sont des nombres entiers positifs dont la somme est inférieure à 1000000000. Vous pouvez également supposer qu'il est toujours possible de se rendre de n'importe quel arrêt à n'importe quel autre arrêt.

【Sortir】

Pour chaque cas, imprimez une ligne contenant le montant minimum d'argent à payer chaque jour par ACM pour les frais de déplacement de ses bénévoles.

【Echantillon d'entrée】

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

【Échantillon de sortie】

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;
}

Guess you like

Origin blog.csdn.net/qq_51800570/article/details/129178858