SDAU数据结构-wentongXu

目录

第一章:线性表

1.1线性表的逻辑结构

1.2单链表的实现

1.3双向链表的实现

1.4课后习题练习

1:约瑟夫环问题

2:单链表的实现

3:有序的双链表的实现

 第二章:栈和队列

2.1:队列

2.1+有关队列的有关题目

2.2:栈

2.2+有关栈的课后题目

6:括号匹配

2.3:有关递归调用的题目

1:逆波兰表达式

2:加数字-递归

3:汉诺塔

图论习题

1.dijkstra求最短路径

2.floyd求最短路径

3.求关键路径

4.拓扑排序

5.kruskal算法求最小生成树

6.prim算法求最小生成树



第一章:线性表

1.1线性表的逻辑结构

线性表的定义:零个或多个具有相同类型的数据元素的有限序列。数据元素的个数定义为线性表的 长度 。长度等于零时称为空表,一个非空表通常记为 L ( a 1 a 2 ……a n ) 。

线形表的实现一般由数组实现和链表实现两种方式。

对于数组实现的线性表:优点是按位置查找时候为o(1)的时间复杂度,但插入和删除操作都是o(n)的时间复杂度

对于链表实现的线性表:优点是插入删除操作为o(1)的时间复杂度,但是按照位置查找的时间复杂度为o(n)

对于空间来说,数组容易出现初始定义不足和后期空间冗余的情况。

1.2单链表的实现

实现模板:

#include<iostream>
#include<algorithm>
using namespace std;
template <class T>
struct Node
{
    T data;
    Node<T> *next;
};
template <class T>
class List
{
    Node<T> *first;
public:
    List();
    List(T a[],int n);
    List(T a[],int n,int k);
    ~List();
    void PrintList();
    int del(int i);
    T Find(int i);
    void Insert(int i,T x) ;
    void Sort();
    void Sort1();
    void Qsort();
    int Length();
    int del_x(T x);
};
template <class T>
List<T>::List()
{
    first=new Node<T>;
    first->next=NULL;
}
/*头插法*/
template <class T>
List<T>::List(T a[],int n)
{
    first=new Node<T>;
    first->next=NULL;
    Node<T> *s;
    for(int i=0; i<n; i++)
    {
        s=new Node<T>;
        s->data=a[i];
        s->next=first->next;
        first->next=s;
    }
}
/*尾插法*/
template <class T>
List<T>::List(T a[],int n,int k)
{
    Node<T> *s,*r;
    first=new Node<T>;
    //first=NULL;
    r=first;
    for(int i=0; i<n; i++)
    {
        s=new Node<T>;
        s->data=a[i];
        r->next=s;
        r=s;
    }
    r->next=NULL;
}
/*查找*/
template <class T>
T List<T>::Find(int i)
{
    Node<T> *p;
    p=first;
    int j=0;
    while(p&&j<i)
    {
        p=p->next;
        j++;
    }
    if(!p)
        throw "查找位置出错" ;
    else
    {
        return p->data;
    }
}
/*删除*/
template <class T>
int  List<T>::del(int i)
{
    //cout<<" "<<Length()<<endl;
    if(i<=0||i>Length())
        return -1;
    Node<T> *p;
    p=first;

    int j=0;
    while(p&&j<i-1) ///找第i-1个的结点
    {
        p=p->next;
        j++;
    }

    if(!p)
        return -1;
    else
    {
        T x=p->next->data;
        p->next=p->next->next;
        return 1;
    }

}
/*删除全部=x的元素*/
template <class T>
int List<T>::del_x(T x)
{
    Node<T> *p,*last;
    p=first;
    last=first;
    int j=0;
    int flag=0;
    while(p)
    {

        last=p;
        p=p->next;

        j++;
        if(!p)
            break;
        ///cout<<p->data<<endl;
        if(p->data==x)
        {
            flag=1;
            T x=last->next->data;
            last->next=last->next->next;
            return 1;
        }
    }
    return flag;


}
/*插入*/
template <class T>
void List<T>::Insert(int i,T x)
{
    Node<T> *p;
    p=first;
    int j=0;
    while(p&&j<i-1) ///找第i-1个的结点
    {
        p=p->next;
        j++;
    }
    if(!p)
        throw "插入位置出错" ;
    else
    {
        Node<T> *temp=new Node<T>;
        temp->data=x;
        temp->next=p->next;
        p->next=temp;
    }
}
/*打印*/
template <class T>
void List<T>::PrintList()
{
    Node<T> *p;
    p=first->next;
    while(p)
    {
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}
template <class T>
void List<T>::Sort()
{
    int len=Length();
    Node<T> *temp,*p;
    for(int i=0; i<len-1; i++)
    {
        p=first->next;
        for(int j=0; j<len-i-1; j++)
        {
            temp=p->next;
            //cout<<temp->data<<endl;
            if((p->data)>(temp->data))
            {
                T x=p->data;
                p->data=temp->data;
                temp->data=x;
            }
            p=p->next;
        }
    }
}
/*长度*/
template <class T>
int List<T>::Length()
{
    Node<T> *p;
    p=first->next;
    int j=1; ///注意从1开始
    while(p)
    {
        p=p->next;
        j++;
    }
    return j-1;
}
template <class T>
List<T>::~List()
{
    Node<T> *p;
    while(first->next)
    {
        p=first->next;
        delete first;
        first=p;
    }
    delete first;

}

1.3双向链表的实现

实现代码:

#include <iostream>
using namespace std;
template<class DataType>
struct Node
{
    DataType data;
    Node<DataType> *next,*from;
};
template<class DataType>
class LinkList
{
    Node<DataType> *head;
public:
    LinkList()
    {
        head = new Node<DataType>;
        head->next=0;
        head->from=0;
    }

    LinkList(DataType a[],int n) //头插法
    {
        Node<DataType> *s;
        head=new Node<DataType>;
        head->next=0;
        head->from=0;
        for(int i=0; i<n; i++)
        {
            s=new Node<DataType>;
            s->data=a[i];
            s->next=head->next;
            head->next=s;
            s->from=head;
            if(s->next!=0)
                s->next->from=s;//下一个节点指向自己
        }
    }

    LinkList(DataType a[],int n,int k)  //尾插法
    {
        Node<DataType>  *s,*r;
        head=new Node<DataType>;
        r=head;
        head->from=0;
        head->next=0;
        for(int i=0; i<n; i++)
        {
            s=new Node<DataType>;
            s->data=a[i];
            r->next=s;
            s->from=r;
            r=s;
        }
        r->next=0;
    }
    void add(DataType a)   //插入
    {  
        Node<DataType> *s;
        s=new Node<DataType>;
        s->data=a;
        s->next=head->next;
        head->next=s;
        s->from=head;
        if(s->next)
                s->next->from=s;
    }
    int del(DataType a)   //按值删除,删除失败返回0,删除成功返回1
    {
        Node<DataType> *s;
        s=head->next;
        while(s){
            if(s->data==a){
                if(s->next==0)
                    s->from->next=0;
                else
                {
                    s->from->next=s->next;
                    s->next->from=s->from;
                }
                delete s; ///....
                return 1;
            }
            s=s->next;
        }
        return 0;
    }
    int len()   //求数组长度
    {
        int n = 0;
        Node<DataType> *s;
        s = head->next;
        while(s!=0)
        {
            n++;
            s = s->next;
        }
        return n;
    }
    int sink(DataType a)   //查找
    {
        int n = 0;
        Node<DataType>*s;
        s = head->next;
        while(s!=0)
        {
            n++;
            if(s->data==a)
                return n;
            s = s->next;
        }
        return 0;
    }
    void show()   //遍历
    {
        Node<DataType> *s;
		s = head->next;
		while(s)
        {
			cout<<s->data<<" ";
			s = s->next;
		}
		cout<<endl;
    }
    void sort1(int n)   //排序
    {
        int t;
        Node<DataType> *s;
        for(int i=0;i<n-1;i++)
        {
            s=head->next;
            for(int j=0;j<n-i-1;j++)
            {
                if(s->data>s->next->data)
                {
                    t=s->data;
                    s->data=s->next->data;
                    s->next->data=t;
                }
                s=s->next;
            }
        }
    }
};

PS:其中实现的时候,last貌似是一个内置的变量,有的时候是通过不了的,直接用了from也是可以的。。。

1.4课后习题练习

1:约瑟夫环问题

描述

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

输入

8 1 3 (n=8 k=1 m=3 )

输出

7 (剩下的那个)

思路:这个题目的话,就是单链表的基础上循环链表的实现了,不过这题目有个坑人的地方就是他一开始的位置有可能是比N还要大的,建议取模一下,不过如果你直接循环过去的话也是可以的; 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define null NULL
using namespace std;
struct Node
{
    int date;
    Node *next;
};
int main()
{
    int n,st,k;
    cin>>n>>st>>k;
    Node *head,*s,*p,*pre;
    head=new Node;
    Node *r=head;
    for(int i=1; i<=n; i++)
    {
        s=new Node;
        s->date=i;
        r->next=s;
        r=s;
        pre=s;
    }
    r->next=head->next;
    head=head->next;
    int cnt=1;
    while(cnt!=st)
    {
        cnt++;
        //cout<<head->date<<"--";
        pre=head;
        head=head->next;
    }
    //cout<<head->date<<endl;
    //cout<<pre->date<<endl;
    cnt=0;
    int ans;
    while(n)
    {
        cnt++;
        if(cnt%k==0)
        {
            ans=head->date;
            pre->next=head->next;
            head=head->next;
            n--;
            //cout<<ans<<" ";
        }
        else
        {
            pre=head;
            head=head->next;
        }
    }
    cout<<ans<<endl;
}

2:单链表的实现

时间限制: 

10000ms

 

内存限制: 

655350kB

描述

定义单链表类,创建带头结点的单链表(节点类型为整型数据),要求包含以下成员函数:

头插法创建单链表(利用构造函数实现)

尾插法创建单链表(重载构造函数实现)

链表的遍历

按值删除一个节点

按位置删除一个节点

链表的析构

 

输入

输入一组数据,以尾插法的形式创建单链表(0表示输入结束)(构造第一个链表)
输入一组数据,以头插法的形式创建单链表(0表示输入结束)(构造第二个链表)
输入要删除元素的值(在尾插法创建的链表中进行改操作)
输入要删除元素的位置(在尾插法创建的链表中进行改操作)

输出

输出尾插法创建链表的结果
输出头插法插法创建链表的结果
输出按值删除之后链表中剩余的元素(若删除的元素不存在,输出Error)
输出按位置删除之后链表中剩余的元素(若删除的元素不存在,输出Error

样例输入

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

样例输出

1 2 3 4 5
5 4 3 2 1
1 3 4 5
Error

思路:基本上就是对于单链表的模板设计了。。 

#include<iostream>
#include<algorithm>
#define null NULL
using namespace std;
const int maxn=10001;
struct Node
{
    int data;
    Node *next;
};

class list
{
    Node *first;
    int sum;
public:
    list(int a[],int len)
    {
        sum=len;
        first=new Node;
        Node *r,*s;
        r=first;
        for(int i=0; i<len; i++)
        {
            s=new Node;
            s->data=a[i];
            r->next=s;
            r=s;
        }
        r->next=null;
    }
    int del(int x)
    {
        int flag=0;
        Node *p,*j;
        p=first;
        j=first;
        while(p)
        {
            p=j;
            j=j->next;
            if(!j)
                break;

            if(j->data==x)
            {
                flag=1;
                p->next=j->next;
                j=j->next;
                sum--;
                return 1;
            }
        }
        return flag;
    }
    int delpos(int pos)
    {
        if(pos<0||pos>=sum)
            return 0;
        Node *p=first;
        Node *pre=first;
        int cnt=0;
        while(p&&cnt<pos)
        {
            p=p->next;
            cnt++;
        }
        if(!p)
            return 0;
        else
        {
            p->next=p->next->next;
            return 1;
        }
    }
    void showall()
    {
        Node *p;
        p=first->next;
        while(p!=null)
        {
            cout<<p->data<<" ";
            p=p->next;
        }
        cout<<endl;
    }
};
int main()
{
    int a[maxn],b[maxn];
    int cnt,x;
    for(cnt=0,cin>>x; x; cnt++)
    {
        a[cnt]=x;
        cin>>x;
    }
    list lis1(a,cnt);
    lis1.showall();

    for(cnt=0,cin>>x; x; cnt++) //偷个懒
    {
        b[cnt]=x;
        cin>>x;
    }
    for(cnt--; cnt>=0; cnt--)
        cout<<b[cnt]<<" ";
    cout<<endl;

    cin>>x;
    if(lis1.del(x))
        lis1.showall();
    else
        cout<<"Error"<<endl;

    cin>>x;
    if(lis1.delpos(x-1))
        lis1.showall();
    else
        cout<<"Error"<<endl;

}

3:有序的双链表的实现

时间限制: 

100000ms

 

内存限制: 

655360kB

描述

定义有序的双链表类,链表中存储整型数据,创建带头结点的有序双链表,要求包含以下成员函数:

双链表的构造函数(非空的链表,输入数据为0,表示输入结束)

插入操作(将一个数据元素插入到有序的双链表中,插入之后链表仍然有序,输入数据为0表示插入操作结束)

按值删除节点(考虑有重复值的情况)

双链表的遍历操作

双链表的析构

 

 

输入

输入链表中的元素,根据输入元素,创建有序双链表(非空的链表,输入数据为0,表示输入结束)
输入要插入的值(可以插入多个值,0表示输入结束,)
输入要删除的值(可以删除多个值,0表示结束,)

输出

输出创建的结果
输出插入的结果
输出删除之后的结果

样例输入

1 6 3 7 5 9 0
8 0
2 0

样例输出

1 3 5 6 7 9
1 3 5 6 7 8 9
1 3 5 6 7 8 9

代码:

#include <iostream>
using namespace std;
template<class DataType>
struct Node
{
    DataType data;
    Node<DataType> *next,*from;
};
template<class DataType>
class LinkList
{
    Node<DataType> *head;
public:
    LinkList()
    {
        head = new Node<DataType>;
        head->next=0;
        head->from=0;
    }

    LinkList(DataType a[],int n) //头插法
    {
        Node<DataType> *s;
        head=new Node<DataType>;
        head->next=0;
        head->from=0;
        for(int i=0; i<n; i++)
        {
            s=new Node<DataType>;
            s->data=a[i];
            s->next=head->next;
            head->next=s;
            s->from=head;
            if(s->next!=0)
                s->next->from=s;//下一个节点指向自己
        }
    }

    LinkList(DataType a[],int n,int k)  //尾插法
    {
        Node<DataType>  *s,*r;
        head=new Node<DataType>;
        r=head;
        head->from=0;
        head->next=0;
        for(int i=0; i<n; i++)
        {
            s=new Node<DataType>;
            s->data=a[i];
            r->next=s;
            s->from=r;
            r=s;
        }
        r->next=0;
    }
    void add(DataType a)   //插入
    {  
        Node<DataType> *s;
        s=new Node<DataType>;
        s->data=a;
        s->next=head->next;
        head->next=s;
        s->from=head;
        if(s->next)
                s->next->from=s;
    }
    int del(DataType a)   //按值删除,删除失败返回0,删除成功返回1
    {
        Node<DataType> *s;
        s=head->next;
        while(s){
            if(s->data==a){
                if(s->next==0)
                    s->from->next=0;
                else
                {
                    s->from->next=s->next;
                    s->next->from=s->from;
                }
                delete s; ///....
                return 1;
            }
            s=s->next;
        }
        return 0;
    }
    int len()   //求数组长度
    {
        int n = 0;
        Node<DataType> *s;
        s = head->next;
        while(s!=0)
        {
            n++;
            s = s->next;
        }
        return n;
    }
    int sink(DataType a)   //查找
    {
        int n = 0;
        Node<DataType>*s;
        s = head->next;
        while(s!=0)
        {
            n++;
            if(s->data==a)
                return n;
            s = s->next;
        }
        return 0;
    }
    void show()   //遍历
    {
        Node<DataType> *s;
		s = head->next;
		while(s)
        {
			cout<<s->data<<" ";
			s = s->next;
		}
		cout<<endl;
    }
    void sort1(int n)   //排序
    {
        int t;
        Node<DataType> *s;
        for(int i=0;i<n-1;i++)
        {
            s=head->next;
            for(int j=0;j<n-i-1;j++)
            {
                if(s->data>s->next->data)
                {
                    t=s->data;
                    s->data=s->next->data;
                    s->next->data=t;
                }
                s=s->next;
            }
        }
    }
};
int main()
{
    int t,i;
    int a[200000];
    for(i=0;cin>>t;)
    {
        if(t==0)
            break;
        else
            a[i++]=t;
    }
    LinkList<int> l1(a,i);
    l1.sort1(l1.len());
    l1.show();
    while(cin>>t)
    {
        if(t==0)
            break;
        else
            l1.add(t);
    }
    l1.sort1(l1.len());
    l1.show();
    while(cin>>t)
    {
        if(t==0)
            break;
        else
            while(l1.del(t)==1);
    }
    l1.sort1(l1.len());
    l1.show();
    return 0;

}

 第二章:栈和队列

2.1:队列

有关队列的模型:

                             

基本上就是这个样子的,先进先出(FIFO);

推荐使用STL中的栈的函数,

其中包括头文件:<queue>

一些库函数: queue<type>Q

  • Q.front() :返回队列首部元素;
  • Q.push():向队列中插入一个元素;
  • Q.pop():弹出队列的首部元素;
  • Q.size():返回当前队列中元素的个数;
  • Q.empty():判断当前队列是否为空;
  • Q.back():返回队列最后一个元素;

可以自己写写代码测试一下

2.1+有关队列的有关题目

有关出栈可行性问题的:https://blog.csdn.net/wentong_Xu/article/details/83046567

2.2:栈

有关栈的模型:

                               

有关栈的话,就是只有一端是进和出的,先进后出(FILO)

有关栈的头文件:<stack>

有关库函数:stack<type>S;

  • S.top():返回栈的首部元素;
  • S.push():向栈的栈首加入一个元素;
  • S.pop():弹出栈的首部;
  • S.size():返回栈的元素个数;
  • S.empty():判断栈是否为空;

2.2+有关栈的课后题目

6:括号匹配

时间限制: 

1000ms

 

内存限制: 

1000kB

描述

假设表达式中只包含三种括号:圆括号、方括号和花括号,它们可相互嵌套,如([{}])或({[][()]})等均为正确的格式,而{[]})}或{[()]或([]}均为不正确的格式.

输入一串括号
如果输入的右括号多余,输出:Extra right brackets
如果输入的左括号多余, 输出:Extra left brackets
如果输入的括号不匹配,输出:Brackets not match
如果输入的括号匹配,输出:Brackets match

输入

{{{{)))

输出

Brackets not match

样例输入

{([)]}

样例输出

Brackets not match

思路:有关栈的操作吧,

首先如果是 左括号,那么我们让他们无条件的进行入栈操作;

如果是右括号,那么我们就需要判断是不是栈的首部是否为与之匹配的括号,如果是的话,那么我们就对栈pop()取出与之匹配的那个括号,防止这个括号对其他括号的匹配造成阻碍

如果右括号不匹配了,那么我们就可以枚举错误然后结束这个判断了,因为他一定是不能正常匹配的,

如果我们到最后发现这个栈中还有元素,也就是还有括号,也是枚举结果输出就可以了,因为到最后剩下的也就是多出来的

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
int main()
{
    char a[10001];
    cin>>a;
    int len=strlen(a);
    stack<char>S;
    for(int i=0;i<len;i++)
    {
        if(a[i] == '(' || a[i] == '[' || a[i] == '{' )
            S.push(a[i]);
        else if(!S.empty())
        {
            char t=S.top();
            S.pop();
            if((a[i] == ')'  && t == '(')||( a[i] == ']' && t == '[') ||(t== '{' && a[i] == '}' ))
                continue;
            else
            {
                cout<<"Brackets not match"<<endl;
                return 0;
            }
        }
        else
        {
            cout<<"Extra right brackets"<<endl;
            return 0;
        }
    }
    if(S.empty())
        cout<<"Brackets match"<<endl;
    else
        cout<<"Extra left brackets"<<endl;
    return 0;
}

 

2.3:有关递归调用的题目

1:逆波兰表达式

时间限制: 

1000ms

 

内存限制: 

65536kB

描述

逆波兰表达式是一种把运算符前置的算术表达式,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) * 4的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括+ - * /四个。

输入

输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出

输出为一行,表达式的值。
可直接用printf("%f\n", v)输出表达式的值v。

样例输入

* + 11.0 12.0 + 24.0 35.0

样例输出

1357.000000

提示

可使用atof(str)把字符串转换为一个double类型的浮点数。atof定义在math.h中。
此题可使用函数递归调用的方法求解。

思路:基本的递归调用吧,其实可以用队列试一下。。。

2:加数字-递归

时间限制: 

10000ms

 

单个测试点时间限制: 

1000ms

 

内存限制: 

34678kB

描述

要求找出具有下列性质的数的个数(包含输入的自然数n):

先输入一个自然数n(n<=500),然后对此自然数按照如下方法进行处理:

1.不作任何处理;

2.在它的左边加上一个自然数,但该自然数不能超过原数首位数字的一半;

3. 加上数后,继续按此规则进行处理,直到不能再加自然数为止.

输入

一个整数n

输出

一个整数,即满足条件的数的个数

样例输入

6

样例输出

6
#include<iostream>
#include<cstdio>
#define inf 0x3f3f3f3f3f
using namespace std;
int cnt;
void search(int n)
{
    if(n==1)
        return ;
    for(int i=1; i<=n/2; i++)
    {
        cnt++;
        //cout<<i<<endl;
        search(i);
    }
}
int main()
{
    cnt=0;
    int n;
    scanf("%d",&n);
    if(n>=100)
        n/=100;
    else if(n>=10)
        n/=10;
    else
        n=n;
    //cout<<n<<endl;
    search(n);
    cout<<cnt+1<<endl;
    return 0;
}

3:汉诺塔

时间限制: 

10000ms

 

内存限制: 

65535kB

描述

给定A、B、C三根足够长的细柱,在A柱上放有n个中间有孔的圆盘,共有n个不同的尺寸,现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An以及移动过程

输入

盘子的个数

输出

移动的移动的路径和次数

样例输入

3

样例输出

move A->C
Move A->B
move C->B
Move A->C
Move B->A
Move B->C
Move A->C
7

思路:其实汉诺塔问题感觉一直很是奇妙的,这个问题的话,自己是模拟了好几遍也包括看视频上的圆盘数量从少到多的一个规律吧:

(1)n == 1

  • 第1次  1号盘  A---->C       sum = 1 次

  (2)  n == 2

  • 第1次  1号盘  A---->B
  •  第2次  2号盘  A---->C
  • 第3次  1号盘  B---->C        sum = 3 次

(3)n == 3

  • 第1次  1号盘  A---->C
  • 第2次  2号盘  A---->B
  • 第3次  1号盘  C---->B
  • 第4次  3号盘  A---->C
  • 第5次  1号盘  B---->A
  • 第6次  2号盘  B---->C
  • 第7次  1号盘  A---->C        sum = 7 次

 基本的汉诺塔规律:

(1)     把n-1个盘子由A 移到 B;

(2)     把第n个盘子由 A移到 C;

(3)     把n-1个盘子由B 移到 C;

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const char a='A',b='B',c='C';
int sum;
void hanio(char a,char b,char c,int n)
{
    if(n==1)
        printf("Move %c->%c\n",a,c),sum++;
    else
    {
        hanio(a,c,b,n-1);
        printf("move %c->%c\n",a,c),sum++;
        hanio(b,a,c,n-1);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    sum=0;
    hanio(a,b,c,n);
    cout<<sum<<endl;
    return 0;
}

图论习题

1.dijkstra求最短路径

总时间限制: 

10000ms

 

内存限制: 

1000kB

描述

给出一个有向图的结构,求某个顶点到另一点的最短路径

输入

若干行整数,第一行有2个数,分别为顶点数v和弧数a,第二行为起点编号s和终点编号e,接下来有a行,每一行有3个数,分别是该条弧所关联的两个顶点编号和弧的权值

输出

第一行为一个整数,为最短路径值
第二行为若干个空格隔开的顶点构成的最短路径序列(用小写字母)
若无最短路径,直接输出no answer

样例输入

6 8
0 3
0 2 10
0 4 30
0 5 100
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60

样例输出

50
v0 v4 v3

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000+10;
const int inf=0x3f3f3f3f;
int dist[maxn][maxn];
int d[maxn];
int vis[maxn];
int n,m,st,en;
int path[maxn];
void white(int x)
{
    if(path[x]==0)
    {
        cout<<"v"<<st<<" ";
        return ;
    }
    white(path[x]);
    cout<<"v"<<path[x]<<" ";
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        scanf("%d%d",&st,&en);
        memset(dist,inf,sizeof(dist));
        memset(vis,0,sizeof(vis));
        memset(path,0,sizeof(path));
        for(int i=1; i<=m; i++)
        {
            int u,v,d;
            scanf("%d%d%d",&u,&v,&d);
            dist[u][v]=d;
            //dist[v][u]=d;
        }
        memset(vis,0,sizeof(vis));
        for(int i=0; i<n; i++)
            if(i==st)
                d[i]=0;
            else
                d[i]=inf;

        for(int i=1; i<=n; i++)
        {
            int x,min_dist=inf;
            for(int y=0; y<n; y++)
                if(!vis[y]&&min_dist>=d[y])
                    min_dist=d[x=y];

            vis[x]=true;

            /*char ch[10];
            ch[0]='v';
            ch[1]='0'+x;
            ch[2]='\0';
            cout<<ch<<endl;*/

            if(x==en)
                break;

            for(int y=0; y<n; y++)
                if(d[y]>d[x]+dist[x][y])
                {
                    path[y]=x;
                    d[y]=d[x]+dist[x][y];
                }
        }
        if(d[en]!=0&&d[en]<inf)
        {
            cout<<d[en]<<endl;
            white(en);
            cout<<"v"<<en;
        }

        else
        {
            cout<<"no answer";
        }
    }
}

2.floyd求最短路径

总时间限制: 

10000ms

 

内存限制: 

1000kB

描述

给出一个有向图的结构,求所有顶点间的最短路径

输入

若干行整数,第一行有2个数,分别为顶点数v和弧数a,接下来有a行,每一行有3个数,分别是该条弧所关联的两个顶点编号和弧的权值

输出

若干行
每行第一个为一个整数,为最短路径值,其余为若干个空格隔开的顶点构成的最短路径序列(用小写字母)
若无最短路径,直接输出no answer

样例输入

3 5
0 1 4
0 2 11
1 0 6
1 2 2
2 0 3

样例输出

4 v0 v1
6 v0 v1 v2
5 v1 v2 v0
2 v1 v2
3 v2 v0
7 v2 v0 v1

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1000+10;
const int inf=0x3f3f3f3f;
int dist[maxn][maxn];
int path[maxn][maxn];
int n,m;
void white(int i,int j)
{
    if(path[i][j]==-1) return ;
    int k=path[i][j];
    white(i,k);
    cout<<'v'<<k<<" ";
    white(k,j);
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(path,-1,sizeof(path));
    memset(dist,inf,sizeof(dist));
    for(int i=1; i<=m; i++)
    {
        int u,v,d;
        scanf("%d%d%d",&u,&v,&d);
        dist[u][v]=d;
    }
    for(int k=0; k<n; k++)
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
            {
                if(k==i||i==j)
                    continue;
                if(dist[i][j]>dist[i][k]+dist[k][j])
                {
                    dist[i][j]=dist[i][k]+dist[k][j];
                    path[i][j]=k;
                }
            }
    bool flag=false;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
        {
            if(dist[i][j]!=inf)
            {
                flag=true;
                cout<<dist[i][j]<<" ";
                cout<<'v'<<i<<" ";
                white(i,j);
                cout<<'v'<<j<<endl;
            }
        }
    if(!flag)
        cout<<"no answer"<<endl;
}

3.求关键路径

总时间限制: 

10000ms

 

单个测试点时间限制: 

1000ms

 

内存限制: 

65536kB

描述

求出所给的AOE-网的关键路径。

输入

若干行整数,第一行有2个数,分别为顶点数v和弧数a,接下来有a行,每一行有3个数,分别是该条弧所关联的两个顶点编号和弧的权值

输出

若干个空格隔开的顶点构成的序列(用小写字母)

样例输入

9 11
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 3

样例输出

v1 v2 v5 v7 v9
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1000+10;
const int inf=0x3f3f3f3f;
int dist[maxn][maxn];
int d[maxn];
int n,m;
int in[maxn];
int path[maxn];
vector<int >G[maxn];
void white(int x)
{
    if(path[x]==0)
    {
        //cout<<'v'<<x<<" ";
        return ;
    }
    white(path[x]);
    cout<<'v'<<path[x]<<" ";
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,z;
        scanf("%d%d%d",&u,&v,&z);
        dist[u][v]=z;
        G[u].push_back(v);
        in[v]++;
    }
    queue<int >Q;
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
            Q.push(i),d[i]=0;
    }
    int maxx=0;
    int last;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        last=u;
        //cout<<path[u]<<" ";
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(d[v]<d[u]+dist[u][v])
            {
                d[v]=d[u]+dist[u][v];
                path[v]=u;
            }
            ///maxx=max(maxx,d[v]);
            Q.push(v);
        }
    }
   /* for(int i=1;i<=n;i++)
        cout<<i<<":"<<path[i]<<" "<<d[i]<<endl;
    cout<<endl;*/
    white(last);
    cout<<'v'<<last<<endl;
}

4.拓扑排序

总时间限制: 

10000ms

 

内存限制: 

1000kB

描述

给出一个图的结构,输出其拓扑排序序列,要求在同等条件下,编号小的顶点在前

输入

若干行整数,第一行有2个数,分别为顶点数v和弧数a,接下来有a行,每一行有2个数,分别是该条弧所关联的两个顶点编号

输出

若干个空格隔开的顶点构成的序列(用小写字母)

样例输入

6 8
1 2
1 3
1 4
3 2
3 5
4 5
6 4
6 5

样例输出

v1 v3 v2 v6 v4 v5
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int maxn=550;
int in[maxn];
int vis[maxn];
vector<int >G[maxn];
int main()
{
    priority_queue<int,vector<int>,greater<int> > Q;
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            G[i].clear();
        while(!Q.empty()) Q.pop();
        memset(in,0,sizeof(in));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            in[y]++;
        }
        for(int i=1;i<=n;i++)
            if(in[i]==0) Q.push(i);
        while(!Q.empty())
        {
            int u=Q.top();Q.pop();
            printf("v%d ",u);
            for(int i=0;i<G[u].size();i++)
            {
                int v=G[u][i];
                if(--in[v]==0)
                    Q.push(v);
            }
        }
        printf("\n");
    }
}

5.kruskal算法求最小生成树

总时间限制: 

10000ms

 

单个测试点时间限制: 

1000ms

 

内存限制: 

65536kB

描述

要求对一个图使用kruskal算法求最小生成树,依次输出选出的边所关联的顶点序列,要求下标较小者在前,如图所示,其顶点序列为1 3 4 6 2 5 3 6 2 3

输入

若干行整数
第一行为两个整数,分别为图的顶点数和边数
第二行开始是该图的邻接矩阵,主对角线统一用0表示,无直接路径的两点用100来表示(保证各边权值小于100)

输出

若干用空格隔开的整数

样例输入

6 10
0 6 1 5 100 100
6 0 5 100 3 100
1 5 0 5 6 4
5 100 5 0 100 2
100 3 6 100 0 6
100 100 4 2 6 0

样例输出

1 3 4 6 2 5 3 6 2 3

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000+10;
const int inf=100;
int F[maxn];
int n,m;
int findset(int x)
{
    if(F[x]==-1) return x;
    return F[x]=findset(F[x]);
}
struct Node
{
    int u,v,dist;
    Node(){}
    Node(int x,int y,int z):u(x),v(y),dist(z){}
    bool operator <(const Node &ags) const
    {
        if(dist==ags.dist)
            return u>ags.u;
        return dist>ags.dist;
    }
};
int main()
{
    memset(F,-1,sizeof(F));
    scanf("%d%d",&n,&m);
    priority_queue<Node >Q;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);
            if(x!=0&&x<inf)
                Q.push(Node(i,j,x));
        }
    for(int i=1;i<=n-1;)
    {
        Node node=Q.top();Q.pop();
        int u=node.u,v=node.v;
        int fu=findset(u),fv=findset(v);
        if(fu!=fv)
        {
            cout<<u<<" "<<v<<" ";
            F[u]=v;
            i++;
        }
    }
}

6.prim算法求最小生成树

总时间限制: 

10000ms

 

单个测试点时间限制: 

1000ms

 

内存限制: 

65536kB

描述

使用prim算法求某图的最小生成树的边的权值输出的序列。例如下图的最小生成树的权值输出序列为1 4 2 5 3,要求从V1顶点开始生成最小生成树。

输入

若干行整数
第一行为两个整数,分别为图的顶点数和边数
第二行开始是该图的邻接矩阵,主对角线统一用0表示,无直接路径的两点用100来表示(保证各边权值小于100)

输出

若干用空格隔开的整数

样例输入

6 10
0 6 1 5 100 100
6 0 5 100 3 100
1 5 0 5 6 4
5 100 5 0 100 2
100 3 6 100 0 6
100 100 4 2 6 0

样例输出

1 4 2 5 3

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1000+10;
const int inf=100;
int dist[maxn][maxn];
int vis[maxn];
int n,m;
struct Node
{
    int u,v,dist;
    Node(){}
    Node(int x,int y,int z):u(x),v(y),dist(z){}
    bool operator <(const Node &ags)const
    {
        if(dist==ags.dist)
            return v>ags.v;
        return dist>ags.dist;
    }
};
vector<int >G[maxn];
priority_queue<Node >Q;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            int x;scanf("%d",&x);
            dist[i][j]=x;
            if(x!=0&&x<=inf)
                G[i].push_back(j);
        }
    for(int i=0;i<G[1].size();i++)
    {
        int v=G[1][i];
        Q.push(Node(1,v,dist[1][v]));
    }
    vis[1]=1;
    for(int i=1;i<=n-1;i++)
    {
        Node node=Q.top();Q.pop();
        int u=node.v;
        vis[u]=1;
        cout<<node.dist<<" ";
        //cout<<node.u<<" "<<node.v<<endl;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(vis[v]==1) continue;
            Q.push(Node(u,v,dist[u][v]));
        }
    }
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值