文章目录

  • 7-1 最大子列和问题
  • 7-2 一元多项式的乘法与加法运算
  • 7-3 树的同构
  • 7-4 是否同一棵二叉搜索树
  • 7-5 堆中的路径
  • 7-6 列出连通集
  • 7-7 六度空间
  • 7-8 哈利·波特的考试
  • 7-9 旅游规划
  • 7-10 公路村村通
  • 7-11 关键活动
  • 7-12 排序
  • 7-11 关键活动
  • 7-13 统计工龄
  • 7-14 电话聊天狂人
  • 总结



7-1 最大子列和问题

const和static的用法没搞清楚!!!

#include <iostream>
//#include <stdio.h>
//#include <stdlib.h>
using namespace std;

int maxSubSequence(int A[], int N)
{
    int ThisSum,MaxSum,j;
    ThisSum = MaxSum =0;

    for(j = 0; j < N; j++)
    {
        ThisSum += A[j];

        if(ThisSum > MaxSum)
            MaxSum = ThisSum;
        else if(ThisSum < 0)
            //将前面已求和的数列看作一个数,大于0就留下
            //小于0的时候就舍弃前面序列重新开始
            //满足题目小于0当作0.
            ThisSum = 0;
    }
    return MaxSum;
}

int main()
{
    int number = 0;
    scanf("%d", &number);
    int sequence[100001];
    for(int i=0; i<number; i++)
    {
        scanf("%d", &sequence[i]);
    }
    printf("%d", maxSubSequence(sequence, number));
    return 0;
}

7-2 一元多项式的乘法与加法运算

在用结构体数组和链表间考虑了一下,配套慕课是用的链表,那就也试试链表,写完看看比数组方便在哪里。

按理来说传入函数后,是个新的作用域了,不传出去,值是不会改变的。改变传入指针的值!!!?

#include <iostream>
using namespace std;

typedef struct PolyNode *Poly;
struct PolyNode{
    int coefficient; //系数
    int exponent; //指数
    Poly next;
};

void create(int c, int e, Poly *tail)
{
    Poly newNode = new PolyNode;
    newNode->coefficient = c;
    newNode->exponent = e;
    newNode->next = NULL;
    //改变传入指针的值!!!
    //头结点是空结点
    (*tail)->next = newNode;
    *tail = newNode;
}

Poly read()
{
    Poly head, tail; //头尾指针
    head = new PolyNode;
    head->next = NULL;
    tail = head;
    int c, e, n;
    scanf("%d", &n);
    while(n--)
    {
        scanf("%d %d", &c, &e);
        create(c, e, &tail); //传入引用还是地址来着?!!!
    }
    return head->next;
}

void printp(Poly head)
{
    Poly p = head;
    if(!p)
    {
        printf("0 0\n");
        return;
    }
    while(p->next)
    {
        printf("%d %d ", p->coefficient, p->exponent);
        p = p->next;
    }
    printf("%d %d\n", p->coefficient, p->exponent);
}

Poly add(Poly p1, Poly p2)
{
    Poly addHead, tail;
    addHead = new PolyNode;
    addHead->next = NULL;
    tail = addHead;
    int tmp = 0;
    while(p1&&p2)
    {
        if(p1->exponent == p2->exponent)
        {
            tmp = p1->coefficient + p2->coefficient;
            if(tmp != 0)
            {
                //这个容易忘记哎
                create(tmp, p1->exponent, &tail);
            }
            p1 = p1->next;
            p2 = p2->next;
        }
        else if(p1->exponent > p2->exponent)
        {
            create(p1->coefficient, p1->exponent, &tail);
            p1 = p1->next;
        }
        else
        {
            create(p2->coefficient, p2->exponent, &tail);
            p2 = p2->next;
        }
    }
    while(p1)
    {
        create(p1->coefficient, p1->exponent, &tail);
        p1 = p1->next;
    }
    while(p2)
    {
         create(p2->coefficient, p2->exponent, &tail);
         p2 = p2->next;
    }
    return addHead->next;
}

Poly mul(Poly p1, Poly p2)
{
    Poly mulHead, tail, tmp;
    tmp = new PolyNode;
    tmp->next = NULL;
    tail = tmp;
    mulHead = NULL;
    int c, e;

//    printf("____________________________\n");
//    printf("p1: ");
//    printp(p1);
//    printf("p2: ");
//    printp(p2);

    if(!p1 || !p2)
    {
        return NULL;
    }
    while(p1)
    {
        Poly t2 = p2;
        while(t2)
        {
            c = p1->coefficient * t2->coefficient;
            e = p1->exponent + t2->exponent;
            create(c, e, &tail);
            t2 = t2->next;
        }
        tmp = tmp->next;

//        printf("tmp: ");
//        printp(tmp);
//        printf("__________________________\n");
        mulHead = add(tmp, mulHead);
        //新的乘积
        tmp->next = NULL;
        tail = tmp;
        p1 = p1->next;
    }
    return mulHead;
}

int main()
{
    Poly p1, p2, pAdd, pMul;
    p1 = read();
    p2 = read();
//    printf("pAdd: ");
//    printf("__________________________\n");
    pMul = mul(p1, p2);
    printp(pMul);
    pAdd = add(p1, p2);
    printp(pAdd);
}

感觉用两种结构体都差不多,因为每次加法和乘法都是开辟新的空间。

7-3 树的同构

完全没思路,连这棵树是怎么读取去构成都不知道。老师讲解视频

两棵树如果是同构的,他们对应节点的儿子是一样的,左右位置可以不同。

解题关键:

1、二叉树表示

一般用链表表示,或者看作完全二叉树用数组表示。这里用一种新的结构去表示。

数据结构与算法 树 习题 数据结构与算法程序题_c语言

2、建二叉树
可以发现Left和Right都是存的左右孩子结点,那么根结点就是没有被存储的那个结点啦,泪目。用.和->去指向结构体某个属性到底是啥区别呢?! 而且为啥输入会不能读取呢?cpp的cin>>用法又是什么

3、同构判别
先写出递归出口,然后分情况讨论递归。

#include <iostream>
using namespace std;

#define ElementType char
#define MaxTree 11
#define Tree int
#define null -1

struct TreeNode
{
    ElementType Element;
    Tree Left;
    Tree Right;
} T1[MaxTree], T2[MaxTree];
//用结构体数组表示二叉树

Tree buildTree(struct TreeNode T[])
{
    int n = 0;
    Tree root = null;
    ElementType left, right;

    scanf("%d", &n);
    if(n)
    {
        int check[n];
        for(int i=0; i<n; i++)
        {
            check[i] = 0;
        }

        for(int i=0; i<n; i++)
        {
            //scanf("%c %c %c\n", &T[i].Element, &left, &right);
            //这样输入的问题是&T.Element根本不会装变量
            //scanf("\n%c %c %c", &T[i].data, &a, &b); //网友的方法
            cin >> T[i].Element >> left >> right;
            if(left == '-')
                T[i].Left = null;
            else
            {
                T[i].Left = left-'0'; //数字字符转为数字的方法
                check[T[i].Left] = 1;
            }
            if(right == '-')
                T[i].Right = null;
            else
            {
                T[i].Right = right-'0';
                check[T[i].Right] = 1;
            }
        }

        for(int i=0; i<n; i++)
        {
            if(!check[i])
            {
                root = i;
                break;
            }
        }
    }
    return root;
}

int isOmorphic(Tree R1, Tree R2)
{
    //分情况递归下去是我没想到的,泪目

    //递归出口
    //根节点为空
    if(R1==null && R2==null)
    {
        return 1;
    }
    //根结点一空一不空
    if(R1*R2<0)
    {
        return 0;
    }
    //根节点值不一样
    if(T1[R1].Element != T2[R2].Element)
    {
        return 0;
    }

    //还不能结束判断
    //如果左子树都空,那么递归判别右子树
    if(T1[R1].Left==null && T2[R2].Left==null)
    {
        return isOmorphic(T1[R1].Right, T2[R2].Right);
    }
    //左边都不空,要判断是不是交换过一次了!!!那对比的左右结点是不同的
    if((T1[R1].Left!=null && T2[R2].Left!=null)&&(T1[T1[R1].Left].Element == T2[T2[R2].Left].Element))
    {
        return ((isOmorphic(T1[R1].Right, T2[R2].Right)) && (isOmorphic(T1[R1].Left, T2[R2].Left)));
    }
    else
    {
         return ((isOmorphic(T1[R1].Right, T2[R2].Left)) && (isOmorphic(T1[R1].Left, T2[R2].Right)));
    }
}

int main()
{
    Tree R1, R2;

    R1 = buildTree(T1);
    R2 = buildTree(T2);

    if(isOmorphic(R1,R2))
        printf("Yes\n");
    else
        printf("No\n");

    return 0;
}

7-4 是否同一棵二叉搜索树

按理来说 有不用把所有树都构造出来的方法。 之后找视频看看吧。

#include <iostream>
using namespace std;

typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode
{
    ElementType Data;
    BinTree Left;
    BinTree Right;
};

void InorderTraversal( BinTree BT )
{//中序
    if(!BT)
    {
        return;
    }
    InorderTraversal( BT->Left );
    printf(" %d",BT->Data);
    InorderTraversal( BT->Right );
}


BinTree Insert( BinTree BST, ElementType X )
{
    BinTree node = (BinTree)malloc(sizeof(struct TNode));
    node->Data = X;
    node->Left = NULL;
    node->Right = NULL;
    if(!BST)
    {
        return node;
    }
    BinTree p = BST;
    while(1)
    {
        if(p->Data > X)
        {
            if(!p->Left)
            {
                p->Left = node;
                return BST;
            }
            p = p->Left;
        }
        else if(p->Data < X)
        {
            if(!p->Right)
            {
                p->Right = node;
                return BST;
            }
            p = p->Right;
        }
    }
}

void Justify( BinTree BT1, BinTree BT2 )
{
    if(!BT1 && !BT2)
    {
        printf("Yes\n");
        return;
    }
    if((!BT1&&BT2) || (BT1&&!BT2))
    {
        printf("No\n");
        return;
    }


    BinTree queen[22];
    BinTree temp1, temp2;
    int front=0, rear=0;
    if(BT1->Data == BT2->Data)
    {
        queen[rear++] = BT1;
        queen[rear++] = BT2;
    }
    else
    {
        printf("No\n");
        return;
    }

    while(front != rear)
    {
        temp1 = queen[front++];
        temp2 = queen[front++];

        if(!temp1->Left && !temp2->Left){}
        else if(temp1->Left->Data == temp2->Left->Data)
        {
            //printf("1: %d\n", temp1->Left->Data);
            //printf("2: %d\n", temp2->Left->Data);
            queen[rear++] = temp1->Left;
            queen[rear++] = temp2->Left;
        }
        else
        {
            printf("No\n");
            return;
        }
        if(!temp1->Right && !temp2->Right){}
        else if(temp1->Right->Data == temp2->Right->Data)
        {
            //printf("1r: %d\n", temp1->Right->Data);
            //printf("2r: %d\n", temp2->Right->Data);
            queen[rear++] = temp1->Right;
            queen[rear++] = temp2->Right;
        }
        else
        {
            printf("No\n");
            return;
        }
    }
    printf("Yes\n");
    return;
}


int main()
{
    BinTree BST, Tmp;
    ElementType X;
    int N, times, i;


    while(1)
    {
        scanf("%d", &N);
        if(!N)
        {
            break;
        }
        scanf("%d",×);

        //读入标准查找树
        BST = NULL;
        for ( i=0; i<N; i++ )
        {
            scanf("%d", &X);
            BST = Insert(BST, X);
        }
        //printf("\n");
        //InorderTraversal(BST);
        //printf("\n");

        while(times--)
        {
            Tmp = NULL;
            for ( i=0; i<N; i++ )
            {
                scanf("%d", &X);
                Tmp = Insert(Tmp, X);
            }
            //printf("\n");
            //InorderTraversal(Tmp);
            //printf("\n");

            Justify(BST, Tmp);
        }

    }
    return 0;
}

7-5 堆中的路径

堆是按照完全二叉树的结构存储的,图解建立最大堆

#include <iostream>
using namespace std;


void Swap(int *arr, int i, int j)
{
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

/*
如果i=0,结点i是根结点,没有双亲结点;否则结点i的双亲结点为(i-1)/2。
如果2* i+1<=n-1,则结点i的左孩子为2*i+1,否则结点i无左孩子。
如果2* i+2<=n-1,则结点i的右孩子为2*i+2,否则结点i无右孩子。
*/

int* BuildMinHeap(int N) {
    int *arr = (int*)malloc(N*sizeof(int));
    int f=0, i=0;
    for(int j=0; j<N; j++)
    {
        i = j;
        scanf("%d", &arr[i]);
        f = (i-1)/2;
        while(f>=0 && arr[i] < arr[f])
        {
            Swap(arr, i, f);
            i = f;
            f = (i-1)/2;
            if(i <= 0)
            {
                break;
            }
        }
    }
    return arr;
}


int main()
{
    int N, M;
    scanf("%d %d", &N, &M);
    if(N)
    {
        int* h = BuildMinHeap(N);
        int index = 0;
        while(M--)
        {
           scanf("%d", &index);
           --index;
           while(index)
           {
               printf("%d ", h[index]);
               index = (index-1)/2;
           }
           printf("%d\n", h[0]);
        }
    }
    return 0;
}

7-6 列出连通集

#include <iostream>
#include <queue>
#include <string.h>

#define Max 11

using namespace std;

int N, E;
int Map[Max][Max];
int flag[Max];

void DFS(int beg)
{
    flag[beg] = 1;
    printf(" %d", beg);
    for(int i=0; i<N; i++)
    {
        if(Map[beg][i]==1 && flag[i]==0)
        {
            DFS(i);
        }
    }
}

void BFS(int beg)
{
    flag[beg] = 1;
    queue<int> q;
    q.push(beg);
    int temp;
    while(!q.empty())
    {
        temp = q.front();
        printf(" %d", temp);
        q.pop();
        for(int i=0; i<N; i++)
        {
            if(Map[temp][i]==1 && flag[i]==0)
            {
               flag[i] = 1;
               q.push(i);
            }
        }
    }

}

int main()
{
    scanf("%d %d", &N, &E);
    memset(Map, 0, sizeof(Map));
    memset(flag, 0, sizeof(flag));
    int x, y;
    while(E--)
    {
        scanf("%d %d", &x, &y);
        Map[x][y] = 1;
        Map[y][x] = 1;
    }

    for(int i=0; i<N; i++)
    {
        if(!flag[i])
        {
            printf("{");
            DFS(i);
            printf(" }\n");
        }
    }

    memset(flag, 0, sizeof(flag));

    for(int i=0; i<N; i++)
    {
        if(!flag[i])
        {
            printf("{");
            BFS(i);
            printf(" }\n");
        }
    }

    return 0;
}

7-7 六度空间

因为结点很多,所以用链表去存储,矩阵存储的话稀疏就很浪费空间和遍历的时间。然后用BFS去入栈连同他自己这个结点,一共入栈7次。但是还是用矩阵写的快,而且难点是判断第几层

有一个原因造成部分错误,就是0.2f是四舍五入,如果写截断反而会报错 printf("%d: %0.2f%%\n", i, ((int)(percentage*100))/100.0);

算百分比不能double = int/int,int/int得到的就是int,只不过变成double单纯加了个小数点再赋值的。这也是容易错误的地方。

#include <iostream>
#include <queue>
#include <string.h>
#include <math.h>

#define Max 1001

using namespace std;

int N, E;
int Map[Max][Max];
int flag[Max];

int BFS(int beg)
{
    flag[beg] = 1;
    int times = 0;
    int sum = 1;
    queue<int> q;

    q.push(beg);
    int temp, last = beg, tail = -1;

    while(!q.empty())
    {
        temp = q.front();
        for(int i=1; i<=N; i++)
        {
            if(Map[temp][i]==1 && flag[i]==0)
            {
               flag[i] = 1;
               tail = i;
               q.push(i);
               sum++;
               //printf("%d--", i);
            }
        }

        q.pop();
        if(last == temp)
        {
            times++;//记住每层入队的最后一个,他出队的时候,就是一层了
            last = tail;
            //printf("\n");
        }
        if(times == 6)
        {
            break;
        }
    }
    return sum;
}

int main()
{
    scanf("%d %d", &N, &E);
    memset(Map, 0, sizeof(Map));
    memset(flag, 0, sizeof(flag));
    int x, y;
    while(E--)
    {
        scanf("%d %d", &x, &y);
        Map[x][y] = 1;
        Map[y][x] = 1;
    }

    double percentage;
    for(int i=1; i<=N; i++)
    {
        percentage = (double)BFS(i)*100/(double)N;
        printf("%d: %0.2f%%\n", i, percentage);
        memset(flag, 0, sizeof(flag));
    }

    return 0;
}

7-8 哈利·波特的考试

无向图的多元最短路径算法;如果图不连通,就直接输出0.小白专场 弗洛伊德算法模板:

bool Floyd_Standard(MGraph Graph, WeightType D[][Max], Vertex path[][Max])
{
    Vertex i, j, k;
    //初始化
    for(i=0; i<Graph->Nv; i++)
    {
        for(j=0; j<Graph->Nv; j++)
        {
            D[i][j] = Graph->G[i][j];
            path[i][j] = -1;
        }
    }
    
    for(k=0; k<Graph->Nv; k++)
    {
        for(i=0; i<Graph->Nv; i++)
        {
            for(j=0; j<Graph->Nv; j++)
            {
                if(D[i][k]+D[k][j] < D[i][j])
                {
                    D[i][j] = D[i][k] + D[k][j];
                    if(i==j && D[i][j]<0) //负值圈要不得
                    {
                        return false; 
                    }
                    path[i][j] = k;
                }
            }
        }
    }
    return true;
}

学习数据结构的定义,也正是因为这些数据结构代码很长。Floyed到底怎么回事?!!

#include <iostream>

using namespace std;

#define Max 101
#define INFINITY 65535 /*双字节无符号整数最大值*/
typedef int Vertex;
typedef int WeightType;

//定义边
typedef struct ENode *PtrToENode;
struct ENode
{
    Vertex V1, V2; //顶点
    WeightType Weight;
};
typedef PtrToENode Edge;

//图结点定义
typedef struct GNode *PtrToGNode;
struct GNode
{
    int Nv; //顶点数
    int Ne; //边数
    WeightType G[Max][Max]; //邻接矩阵
};
typedef PtrToGNode MGraph;

MGraph CreateGraph(int VertexNum)
{
    Vertex V, W;
    MGraph Graph = new GNode;
    Graph->Ne = 0;
    Graph->Nv = VertexNum;
    for(V=0; V<Graph->Nv; V++)
    {
        for(W=0; W<Graph->Nv; W++)
        {
            Graph->G[V][W] = INFINITY;
        }
    }
    return Graph;
}

void InsertEdge(MGraph Graph, Edge E)
{
    Graph->G[E->V1][E->V2] = E->Weight;
    Graph->G[E->V2][E->V1] = E->Weight;
}

MGraph BuildGraph()
{
    int Nv, i;
    scanf("%d", &Nv);
    MGraph Graph = CreateGraph(Nv);

    scanf("%d", &(Graph->Ne));
    if(Graph->Ne != 0)
    {
        Edge E = new ENode;
        for(i=0; i<Graph->Ne; i++)
        {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
            E->V1--;
            E->V2--;
            InsertEdge(Graph, E);
        }
    }
    return Graph;
}

void Floyd(MGraph Graph, WeightType D[][Max])
{
    Vertex i, j, k;
    //初始化
    for(i=0; i<Graph->Nv; i++)
    {
        for(j=0; j<Graph->Nv; j++)
        {
            D[i][j] = Graph->G[i][j];
        }
    }

    for(k=0; k<Graph->Nv; k++)
    {
        for(i=0; i<Graph->Nv; i++)
        {
            for(j=0; j<Graph->Nv; j++)
            {
                if(D[i][k]+D[k][j] < D[i][j])
                {
                    D[i][j] = D[i][k] + D[k][j];
                }
            }
        }
    }
}

WeightType FindMaxDist(WeightType D[][Max], Vertex i, int N)
{
    WeightType MaxDist;
    Vertex j;
    MaxDist = 0;
    for(j=0; j<N; j++)
    {
        if(j!=i && D[i][j]>MaxDist)
        {
            MaxDist = D[i][j];
        }
    }
    return MaxDist;
}

void FindAnimal(MGraph Graph)
{
    int D[Max][Max];
    int Animal, i, MaxDist;
    Floyd(Graph, D);
    int MinDist = INFINITY;
    for(i=0; i<Graph->Nv; i++)
    {
        MaxDist = FindMaxDist(D, i, Graph->Nv);
        if(MaxDist == INFINITY)
        {
            printf("0\n");
            return;
        }
        if(MinDist > MaxDist)
        {
            MinDist = MaxDist;
            Animal = i+1;
        }
    }
    printf("%d %d\n", Animal, MinDist);
}


int main()
{
    MGraph G = BuildGraph();
    FindAnimal(G);
    return 0;
}

7-9 旅游规划

单源最短路径咯,那就迪杰斯特拉算法?但是为啥会保留两条最短的路径?,那么贪心的时候就还要考虑价格少。其实用弗洛伊德也能算,修改的也不多,但是先练习一下迪杰斯特拉算法。

#include <iostream>

using namespace std;

#define Max 501
#define INFINITY 65535 /*双字节无符号整数最大值*/
typedef int Vertex;
typedef int WeightType;

//定义权重结构体
typedef struct WNode *PtrToWNode;
struct WNode
{
    WeightType length; //长度
    WeightType cost; //金额
};
typedef PtrToWNode Weight;

//定义边
typedef struct ENode *PtrToENode;
struct ENode
{
    Vertex V1, V2; //顶点
    Weight W;
};
typedef PtrToENode Edge;

//图结点定义
typedef struct GNode *PtrToGNode;
struct GNode
{
    int Nv; //顶点数
    int Ne; //边数
    int departure; //出发地
    int destination; //目的地
    WNode G[Max][Max]; //邻接矩阵
};
typedef PtrToGNode MGraph;

MGraph CreateGraph(int VertexNum)
{
    Vertex V, W;
    MGraph Graph = new GNode;
    Graph->Ne = 0;
    Graph->Nv = VertexNum;
    Graph->departure = -1; //出发地
    Graph->destination = -1; //目的地
    for(V=0; V<Graph->Nv; V++)
    {
        for(W=0; W<Graph->Nv; W++)
        {
            Graph->G[V][W].cost = INFINITY;
            Graph->G[V][W].length = INFINITY;
        }
    }
    return Graph;
}

void InsertEdge(MGraph Graph, Edge E)
{
    Graph->G[E->V1][E->V2].cost = E->W->cost;
    Graph->G[E->V2][E->V1].cost = E->W->cost;
    Graph->G[E->V1][E->V2].length= E->W->length;
    Graph->G[E->V2][E->V1].length = E->W->length;

}

MGraph BuildGraph()
{
    int Nv, i;
    scanf("%d", &Nv);
    MGraph Graph = CreateGraph(Nv);

    scanf("%d %d %d", &(Graph->Ne), &(Graph->departure), &(Graph->destination));

    if(Graph->Ne != 0)
    {
        Weight W = new WNode;
        Edge E = new ENode;
        E->W = W;
        for(i=0; i<Graph->Ne; i++)
        {
            scanf("%d %d %d %d", &E->V1, &E->V2, &E->W->length, &E->W->cost);
            InsertEdge(Graph, E);
        }
    }
    return Graph;
}

void dijkstra(MGraph p){
    int vis[p->Nv], dis[p->Nv], pay[p->Nv];
    for(int i=0; i<p->Nv; i++)
    {
        vis[i] = 0;
        dis[i] = INFINITY;
        pay[i] = INFINITY;
    }
    int beg = p->departure;
    dis[beg] = 0;
    pay[beg] = 0;


    for(int i=0; i<p->Nv; i++)
    {
        int minDis = INFINITY;
        int minCost = INFINITY;
        int u;
        for(int j=0; j<p->Nv; j++)
        { /*找没被遍历过的距离最小的一个,去贪心*/
            if(!vis[j] && dis[j]<minDis)
            {
                minDis = dis[j];
                u = j;
                minCost = pay[j];
            }
        }
        vis[u] = 1;
        //printf("-------------------------------");
        //printf("当前出发点%d\n", u);

        /* 更新这个正在贪心点的邻接点的到达距离和花费 */
        for(int j=0; j<p->Nv; j++)
        {
            int next;
            while(p->G[u][j].length == INFINITY)
            { //找到一个可达邻接点
                j++;
            }
            next = j;
            //printf("遍历结点:%d\n", j);
            if(!vis[next] && minDis+p->G[u][j].length < dis[next])
            {
                dis[next] = minDis + p->G[u][j].length;
                //printf("距离%d", dis[next]);
                pay[next] = minCost + p->G[u][j].cost;
                //printf("价格%d\n", pay[next]);
            }
            else if(!vis[next] && minDis+p->G[u][j].length==dis[next])
            { //因为不需要记录路径,所以直接更新花费
                if(minCost+p->G[u][j].cost < pay[next])
                {
                    pay[next] = minCost+p->G[u][j].cost;
                    //printf("价格%d\n", pay[next]);
                }
            }
        }
    }
    printf("%d %d", dis[p->destination], pay[p->destination]);
}


int main()
{
    MGraph G = BuildGraph();
    dijkstra(G);
    return 0;
}

我只能说核心代码要反复看,跟着思路走,不然很容易忘!

7-10 公路村村通

这是一个最小生成树问题,特点是:1、无回路;2、n个顶点就有n-1条边;3、包含全部图里的点;4、生成树的所有边都在图里的;5、边的权重和最小。

最小生成树存在<-------->连通图

贪心算法,每次都找权重最小的边,但是约束有:1.只能用图中有的边;2.只能正好用掉顶点数减一条边;3.不能有回路。

Prim算法与Dijkstra算法具有相似的地方。稠密图更加划算。这篇讲的真不错,特别是后面那张图

数据结构与算法 树 习题 数据结构与算法程序题_c++_02


这个要多复习呀,不然就忘啦

#include <iostream>
#include <string.h>

using namespace std;

#define Max 1001
#define INFINITY 65535 /*双字节无符号整数最大值*/
typedef int Vertex;
typedef int WeightType;

//定义边
typedef struct ENode *PtrToENode;
struct ENode
{
    Vertex V1, V2; //顶点
    WeightType pay; //花费
};
typedef PtrToENode Edge;

//图结点定义
typedef struct GNode *PtrToGNode;
struct GNode
{
    int Nv; //顶点数
    int Ne; //边数
    WeightType G[Max][Max]; //邻接矩阵
};
typedef PtrToGNode MGraph;

MGraph CreateGraph(int VertexNum)
{
    Vertex V, W;
    MGraph Graph = new GNode;
    Graph->Ne = 0;
    Graph->Nv = VertexNum;
    for(V=0; V<Graph->Nv; V++)
    {
        for(W=0; W<Graph->Nv; W++)
        {
            Graph->G[V][W] = INFINITY;
        }
    }
    return Graph;
}

void InsertEdge(MGraph Graph, Edge E)
{
    Graph->G[E->V1][E->V2] = E->pay;
    Graph->G[E->V2][E->V1] = E->pay;
}

MGraph BuildGraph()
{
    int Nv, i;
    scanf("%d", &Nv);
    MGraph Graph = CreateGraph(Nv);

    scanf("%d", &(Graph->Ne));
    if(Graph->Ne != 0)
    {
        Edge E = new ENode;
        for(i=0; i<Graph->Ne; i++)
        {
            scanf("%d %d %d", &E->V1, &E->V2, &E->pay);
            E->V1--;
            E->V2--;
            InsertEdge(Graph, E);
        }
    }
    return Graph;
}

void prim(MGraph p)
{
    int i, j;
    int minNode;    //记录新纳入的点
    int minPay;    //记录新纳入的点到其余已纳入的点的最小权值
    int sum = 0;    //最小生成树权值和
    int dis[p->Nv], flag[p->Nv]; //记录纳入点权重,是否纳入该点到树中

    memset(dis, INFINITY, sizeof(dis));  //初始化dis数组为无穷大
    memset(flag, 0, sizeof(flag));  //初始化flag数组,0表示此点未被纳入

    /*这里随机选取了0号点为初始时被纳入的顶点*/
    for(i=0; i <= p->Nv; i++)
        dis[i] = p->G[0][i];     //与1号点与其他点的权值存入dis数组
    dis[0] = 0;         //一号点到其本身的权值为0
    flag[0] = 1;        //标记为已纳入


    for(i = 1; i < p->Nv; i++)
    {   //除去初始时随机纳入的点还有n-1个点应被纳入
        minNode = minPay = INFINITY;

        //寻找其邻接的没纳入的权值最小的点
        for(j=0; j<p->Nv; j++)
        {
            if(flag[j] == 0)
            {
                if(dis[j] < minPay)
                {
                    minNode = j;
                    minPay = dis[j];
                }
            }
        }

        if(minNode == INFINITY) //该的点邻接的点已全被纳入
            break;

        sum += minPay;     //将找到的点纳入并标记
        flag[minNode] = 1;


        for(j = 1; j <= p->Nv; j++){
            //我加入了新的点,那么我要把新的点他到其他点的最短距离更新
            if(flag[j] == 0)
                if(dis[j] > p->G[minNode][j])//新的加入点到没被更新的点的距离!!!能避免回路
                    dis[j] = p->G[minNode][j];
        }

    }


    if(i == p->Nv)      //若i等于n则证明已经建立最小生成树
        printf("%d\n", sum);
    else
        printf("-1");
}


int main()
{
    MGraph G = BuildGraph();
    prim(G);
    return 0;
}

当顶点和边同一数量级可以用Kruskal算法贪心。直接从最小权重的边在不构成回路情况下贪心每个边,最后由森林组成树。

数据结构与算法 树 习题 数据结构与算法程序题_Data_03

7-11 关键活动

7-12 排序

三种语言写的快排模板

7-11 关键活动

没通过的案例和这位同学一样懒猫老师数据结构

#include <iostream>
#include <queue>

using namespace std;


/**
* 算法本身难理解
* 数据结构采用邻接表
* 为了判断图是不是有向无环图,拓扑排序
* 有环的图是不能构成路径的
* 关键路径:带权有向无环图
**/

const int MAX_VERTEX = 101;

//边表
struct ArcNode
{
    int adjvex; //弧终点
    int weight; //权重
    ArcNode *next;
};

//顶点表
struct VertexNode
{
    int vertex; //图的结点信息·
    int in; //图的入度,用于拓扑排序
    ArcNode *firstEdge;
};

/**
* 关键活动有关量:
* 事件最早发生时间ve[k]
* 事件最迟发生时间vl[k]
* 活动最早开始时间ee[i]
* 活动最晚开始时间ev[i]
* 各个活动时间余量el[k]-ee[k],=0即是关键活动
**/

class ALGraph
{
private :
    VertexNode *adjList; //邻接表
    int vertexNum, arcNum;
    int *ve, *vl;
public:
    ALGraph(int v[], int n, int e); //构造函数
    ~ALGraph(); //销毁
    void inputEdges();
    bool setEdge(int vi, int vj, int weight);
    void  displayData();

    bool TopologicalSort(int result[], int &count);
    bool GriticalPath();
};

ALGraph::ALGraph(int v[], int n, int e)
{
    vertexNum = n;
    arcNum = e;
    adjList = new VertexNode[vertexNum];
    for(int i=0; i<vertexNum; i++)
    {
        adjList[i].in = 0;
        adjList[i].vertex = v[i];
        adjList[i].firstEdge = NULL;
    }
    ve = new int[vertexNum];
    vl = new int[vertexNum];
}

bool ALGraph::setEdge(int vi, int vj, int weight)
{
    ArcNode *s;
    if(vi>=0 && vi<vertexNum && vj>=0 && vj<vertexNum && vi!=vj)
    {
        s = new ArcNode;
        s->adjvex = vj;
        s->weight = weight;
        //头插法
        s->next = adjList[vi].firstEdge;
        adjList[vi].firstEdge = s;
        adjList[vj].in++; //入度
        return true;
    }
    else
    {
        //printf("----%d %d %d----", vi, vj, vertexNum);
        return false;
    }
}

void ALGraph ::inputEdges()
{
    for(int i=0; i<arcNum; i++)
    {
        int vi, vj, weight;
        cin >> vi >> vj >> weight;
        if(!setEdge(vi-1, vj-1, weight)) //因为是从0开始存储,并且计数
        {
            //cout << "输入越界" <<endl;
            i--;
        }
    }
}

ALGraph::~ALGraph()
{
    ArcNode *p, *pre;
    for(int i=0; i<vertexNum; i++)
    {
        p = adjList[i].firstEdge;
        adjList[i].firstEdge = NULL;
        while(p)
        {
            pre = p;
            p = p->next;
            delete pre;
        }
    }
    delete [] adjList;
    delete [] ve;
    delete [] vl;
}

bool ALGraph::TopologicalSort(int result[], int &count)
{
    int stack[MAX_VERTEX]; //把顶点对应下标压入栈
    int top = -1;
    int inVex;
    int outVex;
    ArcNode *p;

    for(int i=0; i<vertexNum; i++)
    {
        ve[i] = 0; //最早发生时间初始化为0
    }

    //遍历顶点表,把入度为0的压入堆栈
    for(int i=0; i<vertexNum; i++)
    {
        if(adjList[i].in == 0)
        {
            stack[++top] = i;
        }
    }

    count = 0; //处理过的顶点
    while(top != -1)
    {
        inVex = stack[top--];
        result[count] = inVex; //拓扑排序的序列
        count++;

        p = adjList[inVex].firstEdge;
        while(p)
        {
            outVex = p->adjvex;
            adjList[outVex].in--;
            if(adjList[outVex].in == 0)
            {
                stack[++top] = outVex;
            }
            if(ve[inVex]+p->weight > ve[outVex])
            {
                ve[outVex] = ve[inVex] + p->weight;
            }
            p = p->next;
        }
    }

    if(count == vertexNum)
    {
        return true;
    }
    else
    {
        return false;
    }
}


bool ALGraph::GriticalPath()
{
    int resultStack[MAX_VERTEX];
    int resultTop;
    ArcNode *p;
    int i, count;
    int inVex, outVex;

    if(!TopologicalSort(resultStack, count))
    {
        return false;
    }
//    cout << "拓扑排序处理顺序为:";
//    for(i=0; i<count; i++)
//        cout << resultStack[i] << " ";
//    cout << endl;
//    cout << "ve数组值为:" << endl;
//    for(i=0; i<count; i++)
//        cout<<"ve[" << i << "]=" << ve[i] << endl;

    resultTop = count - 1;
    inVex = resultStack[resultTop--];

    for(i=0; i<vertexNum; i++)
    {
        vl[i] = ve[inVex];
    }

    while(resultTop != -1)
    {
        inVex = resultStack[resultTop--];
        p = adjList[inVex].firstEdge;
        while(p)
        {
            outVex = p->adjvex;
            if(vl[inVex]>vl[outVex] - p->weight)
            {
                vl[inVex] = vl[outVex] - p->weight;
            }
            p = p->next;
        }
    }

    //输出关键路径
    int sum = 0;
    queue< int > q;
    int head, tail;
    bool flag = true;
    for(inVex = 0; inVex<vertexNum; inVex++)
    {
        p = adjList[inVex].firstEdge;
        while(p)
        {
            outVex = p->adjvex;
            int weight = p->weight;
            int ee = ve[inVex];
            int el = vl[outVex]-weight;

            if(ee == el)
            {//当存在多条路径时
                if(flag)
                {
                   flag = false;
                   head = inVex+1;
                   tail = outVex+1;
                   sum += weight;
                }
                if(head == outVex+1)
                {
                    head = inVex+1;
                    sum += weight; //有多条路径时会算错
                }
                if(tail == inVex+1)
                {
                    tail = outVex+1;
                    sum += weight; //有多条路径时会算错
                }
                q.push(inVex+1);
                q.push(outVex+1);
                //cout << "<" << inVex+1 << ","<< outVex+1 << ">" << weight << " "; //因为是从0开始存,所以得+1再输出
            }
            p = p->next;
        }
    }
    printf("%d\n", sum);
    while(!q.empty())
    {
        printf("%d->", q.front());
        q.pop();
        printf("%d\n", q.front());
        q.pop();
    }
    return true;
}

int main()
{
    int vertex[MAX_VERTEX];
    int num, edge;

    cin>>num>>edge;
    for(int i=0; i<num; i++)
    {
        vertex[i] = i+1;
    }

    ALGraph graph(vertex, num, edge);
    graph.inputEdges();
    //graph.displayData();

    if(!graph.GriticalPath())
    {
        cout << 0;
    }
    return 0;
}

7-13 统计工龄

傻了,开始还准备排个序,直接只有0到50的工龄开个数组去记录不就好了。

7-14 电话聊天狂人

陈越姥姥讲聊天狂人


总结

因为实习和毕设的原因刷题就暂停了,之后大概率不会使用Java做题了