2021-06-10

 数据结构第六次上机实验

一、高精度数:

   题意:实现高精度数的加法运算。

   思路:用数组来存放数的所有数位,为了进位方便,我们选择倒叙存储。

   完整代码:

#include<bits/stdc++.h>
using namespace std;
int const max0=2000;

int a[max0],b[max0],sum[max0];
int main()
{    for(int i=0;i<max0;i++)
            {
               sum[i]=0;
            }
    int N;
    cin>>N;
    int start=max0-1;
    for(int i=0;i<N;i++)
        {
            char buffer[150];
            scanf("%s",buffer);
            int len=strlen(buffer);
            int ed=len-1;
//            cout<<len;
            for(int i=0;i<len;i++)
            {sum[i]=sum[i]+buffer[ed--]-'0';
//            cout<<sum[i];
            }
        }
//        cout<<endl;


    for(int i=0;i<max0;i++)
    {
        if(sum[i]>=10)
            {   int chu=sum[i]/10;
                sum[i]=sum[i]%10;
                sum[i+1]+=chu;
            }


    }
    int j=max0-1;
    int k=0;
    while(sum[j]==0)
    {
        k++;
        j--;
    }
//    cout<<k<<endl;
    for(int i=max0-k-1;i>=0;i--)
    {
        cout<<sum[i];
    }
    return 0;
}

 

二、二叉树加权距离

题意:两个结点的加权距离,即上溯到根节点后下溯到目标节点,或直接上溯目标节点,或下溯目标节点。

思路:我们都知树是一种特殊的图,根据题意,我们在建图(树)过程中,两个结点u,v之间可同时建立两条有向边,u->v的边权为2,v->u的边权为3,以此来达到上溯代价为3,下溯代价为2的目的。然后一遍dijkstra(采用了堆优化)。即可。

代码:

1、建图

struct edge{
    int to;
    int cost;
    int parent;
    edge(int t,int c):to(t),cost(c){

    }
};




for(int i = 0;i<m;i++){
        scanf("%d%d",&a,&b);
        g[a].push_back(edge(b,2));
        g[b].push_back(edge(a,3));
    }

2、完整代码

#include<bits/stdc++.h>//该算法适用于稀疏图,稠密图,用于弗洛伊德
#define INF 100000005
#define MAX 100006
using namespace std;
typedef pair<int,int> P;
struct edge{
    int to;
    int cost;
    int parent;
    edge(int t,int c):to(t),cost(c){

    }
};
int length(int s0);
const int N = 100006;
vector<edge> g[N];
int dis[100][100],cd[100000]; //距离
int n,m; //n个点 m条边
//int path[100][100];//最小生成路的长度
int path[100000];
int D[100000];
void Dijkstra(int s){
    static int countdij=0;
    priority_queue<P,vector<P>,greater<P> > que; //小端优先队列
    fill(D,D+100005,INF);//注意必须初始化为最大
    D[s] = 0;
    if(s==0)
    for(int i=0;i<n;i++)
        path[i]=-1;
    que.push(P(0,s));
    while(!que.empty())
        {
        P p = que.top();
        que.pop();
        int v = p.second;
        if(D[v] < p.first) continue; //说明该点无需重复
        for(int i = 0;i<g[v].size();i++) {
            //遍历所有后续边
            edge e = g[v][i];
            int to = e.to;
            int cost = e.cost;
            if(D[to] > D[v] + cost){
                D[to] = D[v] + cost;

                que.push(P(D[to],to));
            }

        }
    }
}


int main(){

    int s=1,u,v;
    cin>>n;//m为边数,n为点数
    m=n-1;

    int a,b,d;
    //Vector<edge> g[MAX]的初始化
    for(int i = 0;i<MAX;i++) {
        g[i].clear();
    }
    for(int i = 0;i<m;i++){
        scanf("%d%d",&a,&b);
        g[a].push_back(edge(b,2));
        g[b].push_back(edge(a,3));
    }
    cin>>u>>v;
    Dijkstra(u);
    int k;

cout<<D[v];
//cout<<"0";
 cout<<endl;


    return 0;
}

 

三、修轻轨

题意:求修建由1到n的轻轨最少修建时间

思路:该题可由最短路问题求解。采用kruskal和并查集判断求解。我们将所有的交通枢纽抽象成一个点,每个点代表一个集合,每次合并集合时我们判断1,n是否在一个集合里。若在则这次加的边即为所求,若不在则继续加边。这题时间点卡的很好,并查集如果不按秩合并的话会超时。

代码:

1、关键代码

void kruskal()
{
    int n,m0;
    int l=0;
    cin>>n>>m0;
            for(int k=0;k<m0;k++)
                    {   int i,j,weight=0;

                        cin>>i>>j>>weight;
                        E[l].head=i;
                        E[l].tail=j;
                        E[l].cost=weight;
                        l++;

                    }

     for(int i=1;i<=n;i++)
       father[i]=i;

    for(int i=1;i<=n;i++)
    {

        rank0[i]=0;
    }
    int T=n;
    m=l;
    sort(E,E+m,cmp);
    int j=0,ss=0;
    int count=0;
    while(T>1)
    {
        int v1=E[j].head;
        int v2=E[j].tail;
        int cost=E[j].cost;
        if(find_set(v1)!=find_set(v2))
        {
            TE[count].head=v1;
            TE[count].tail=v2;
            TE[count].cost=cost;
            count++;
            Union(v1,v2);
            T--;
        }
       
        if(find_set(1)==find_set(n))
        {
            ss=cost;
           break;

        }
        j++;

    }
//    for(int i=1;i<n;i++)
//        cout<<make_set[i]<<" ";

   cout<<ss;

}

2、完整代码


#include<vector>
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;
typedef vector<vector<int>> Mat;
const int max0=99999;
struct node
{
    int head;
    int tail;
    int cost;
}E[200010],TE[200010];
int make_set[1001],m;
int rank0[200100];
int cmp(node a,node b);
int find_set(int x);
int father[100000];

void Union(int x,int y);
void kruskal();//克鲁斯卡尔求最小生成树:适用于边稀疏图


void kruskal()
{
    int n,m0;
    int l=0;
    cin>>n>>m0;
            for(int k=0;k<m0;k++)
                    {   int i,j,weight=0;

                        cin>>i>>j>>weight;
                        E[l].head=i;
                        E[l].tail=j;
                        E[l].cost=weight;
                        l++;

                    }

     for(int i=1;i<=n;i++)
       father[i]=i;

    for(int i=1;i<=n;i++)
    {

        rank0[i]=0;
    }
    int T=n;
    m=l;
    sort(E,E+m,cmp);
    int j=0,ss=0;
    int count=0;
    while(T>1)
    {
        int v1=E[j].head;
        int v2=E[j].tail;
        int cost=E[j].cost;
        if(find_set(v1)!=find_set(v2))
        {
            TE[count].head=v1;
            TE[count].tail=v2;
            TE[count].cost=cost;
            count++;
            Union(v1,v2);
            T--;
        }
       
        if(find_set(1)==find_set(n))
        {
            ss=cost;
           break;

        }
        j++;

    }
//    for(int i=1;i<n;i++)
//        cout<<make_set[i]<<" ";

   cout<<ss;

}
int cmp(node a,node b)
{
    return a.cost<b.                                                                                                                                                                                                   cost;
}
int find_set(int v)
{

   if(father[v]==v) return v;
   return find_set(father[v]);
}
void Union( int x , int y)
{
     int fx = find_set(x);
     int fy = find_set(y);
     if(rank0[fx]<=rank0[fy])
     {
         father[fx]=fy;
         if(rank0[fx]==rank0[fy])
            rank0[fy]++;

     }
    else {
        father[fy]=fx;
    }

}
int main()
{

    kruskal();


    return 0;
}
















四、数据结构设计

题意:建立一个能够对数据高效的进行插入,删除,取反,取最大的动态数据表。

思路:本题太良心了,纯暴力方法都可拿70分,若想拿满分,还需要对取反操作进行优化。我采用了multiset和一个取反标志flag。每取一次反,flag++。

代码:

1、暴力求解代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000;
const int INF=99999999;
int q[1000000],maxs[400000],sum=0;
inline int maxq(int *q,int f,int r);
int main()
{   char  a;
    int r=0,f=0;
    int T=0,k=0;
    cin>>T;
    for(int i=0;i<T;i++)
    {


            cin>>a;
            if(a=='I')
            {
                int x;
                cin>>x;
                q[r]=x;
                r=(r+1)%maxn;
            }
            else if(a=='D')
            {   if(f==r) continue;
                else f=(f+1)%maxn;
            }
            else if(a=='R')
            {
                int s=f;
                for(;s!=r+1;s++)
                {
                    q[s]=-1*q[s];
                }
            }
            else if(a=='M')
            {   int max0;
                if(f==r) continue;
                    else {
                            max0=maxq(q,f,r);
                            maxs[sum++]=max0;
                            }
            }





    }
    cout<<sum;
 for(int i=0;i<sum;i++)
        {
            cout<<maxs[i];
            if(i<sum-1) cout<<"\n";
        }
    return 0;
}
int maxq(int q[],int f,int r)
{

    int m=-1*INF;

    for(;f!=r;f++)
    {
        if(q[f]>m)
          m=q[f];

    }

    return m;

}

2、优化后的代码:

1)、关键代码-----取反和取最大操作

 if(a[0]=='D')
            {   if(q.empty()) continue;
                auto aa=setq.find(q.front());
                setq.erase(aa);
                 q.pop();
            }
            else if(a[0]=='R')
            {
                flag++;

            }
            else if(a[0]=='M')
            {   if(q.empty()) continue;

                if(flag%2!=0)
                {int temp=*(setq.begin());
                 printf("%d\n",-temp);

                }
                    else {
                            int temp=*(setq.rbegin());
                            printf("%d\n",temp);

                         }
            }

2)、完整代码

#include<bits/stdc++.h>
#include<stdio.h>
using namespace std;
const int maxn=200000;
const int INF=99999999;

multiset<int>setq;
queue<int>q;
int main()
{   char  a[10];
    int T,flag=0;
    int x;
    cin>>T;
    for(int i=0;i<T;i++)
    {

            scanf("%s",a);
            if(a[0]=='I')
            {

                scanf("%d",&x);
                if(flag%2!=0)
                {
                    x=-x;
                }
                q.push(x);
                setq.insert(x);
            }
            else if(a[0]=='D')
            {   if(q.empty()) continue;
                auto aa=setq.find(q.front());
                setq.erase(aa);
                 q.pop();
            }
            else if(a[0]=='R')
            {
                flag++;

            }
            else if(a[0]=='M')
            {   if(q.empty()) continue;

                if(flag%2!=0)
                {int temp=*(setq.begin());
                 printf("%d\n",-temp);

                }
                    else {
                            int temp=*(setq.rbegin());
                            printf("%d\n",temp);

                         }
            }

    }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值