PAT(甲级)2020年秋季考试

1. 全网最详细且有注释的代码,有错误给老子指出,但是老子也不改

7-1

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

/*
    这道题的核心思路在于寻找低谷,比如样例中的100和138,然后数据向两边扩散
    1.从左往右开始遍历,初始值设置为200,如果右边的值比左边大则加100;如果右边的值等于左边的值则牛奶量不变;如果右边的值比左边的值小则修改为200,这样一定是能找到低谷
    你想,第一个数设置为200,后面如果体重比它大则往上升,如果相同则区域平静,如果小则还是200,所以一定能找到低谷
    2.同样从右向左按上述方法再次遍历,同样也能找到低谷
    3.这样取同一位置中,两个vector较大的值,因为处于低谷附近所能找到的就是最终的结果

*/

const int maxn=10003;

struct node
{
    
    
    int milk;
    int weight;
}Node[maxn];

vector<int> LR,RL;

int n;

int main()
{
    
    
    cin >> n;
    for(int i=0; i<n; i++)
    {
    
    
        cin >> Node[i].weight;
    }
    Node[0].milk=200;
    LR.push_back(Node[0].milk);
    for(int i=1; i<n; i++)
    {
    
    
        if(Node[i].weight>Node[i-1].weight)
        {
    
    
            Node[i].milk=Node[i-1].milk+100;
        }
        else if(Node[i].weight==Node[i-1].weight)
        {
    
    
            Node[i].milk=Node[i-1].milk;
        }
        else
        {
    
    
            Node[i].milk=200;
        }
        LR.push_back(Node[i].milk);
    }

    Node[n-1].milk=200;
    RL.push_back(Node[n-1].milk);

    for(int i=n-2; i>=0; i--)
    {
    
    
        if(Node[i].weight>Node[i+1].weight)
        {
    
    
            Node[i].milk=Node[i+1].milk+100;
        }
        else if(Node[i].weight==Node[i+1].weight)
        {
    
    
            Node[i].milk==Node[i+1].milk;
        }
        else
        {
    
    
            Node[i].milk=200;
        }
        RL.push_back(Node[i].milk);
    }

    reverse(RL.begin(),RL.end());

    int sum=0,temp;
    for(int i=0; i<n; i++)
    {
    
    
        temp=max(LR[i],RL[i]);
        sum+=temp;
    }
    cout << sum;
}

2

7-2

#include<iostream>
using namespace std;

const int maxn=10003;

int a[maxn];

int n,money,temp;

void DFS(int index, int sum, int num)
{
    
    
    if(index>=n || sum>money)
    {
    
    
        temp=num;
        return ;
    }
    DFS(index+1,sum+a[index+1],num+1);  //注意这里必须是num+1而不是num++,因为如果是num++
}

int main()
{
    
    
    cin >> n >> money;
    int all=0;
    for(int i=0; i<n; i++)
    {
    
    
        cin >> a[i];
    }
    for(int i=0; i<n; i++)
    {
    
    
        DFS(i,a[i],0);
        all+=temp;
    }
    cout << all;
    return 0;
}

7-3

//前序+中序 构建树 然后在 输出左视图==层序遍历法的最左边的值
#include<iostream>
#include<queue>
#include<vector>
using namespace std;

const int maxn=21;

int Pre[maxn],In[maxn];

vector<int> cigar;

struct node
{
    
    
    int data;
    node *lchild;
    node *rchild;
};

node *create(int inL, int inR, int preL, int preR)
{
    
    
    node *root=new node;
    root->data=Pre[preL];
    if(preL>preR)         //注意建树过程中必须有这个
        return NULL;
    int k;
    for(k=inL; k<=inR; k++)
    {
    
    
        if(In[k]==Pre[preL])
        {
    
    
            break;
        }
    }
    int num=k-inL;
    root->lchild=create(inL,k-1,preL+1,preL+num);
    root->rchild=create(k+1,inR,preL+num+1,preR);
}

void layer(node *root)
{
    
    
    queue<node*> q;
    q.push(root);
    while(!q.empty())           //队列q每次只放当前的一层值,对于子孩子直接插入到队列的后面,对于左视图而言,每次只要当前层的第一个值,也就是i==0的时候将数插入到vector中
    {
    
    
        int ans=q.size();
        for(int i=0; i<ans; i++)
        {
    
    
            node *top=q.front();
            if(i==0)
            {
    
    
                cigar.push_back(top->data);
            }
            if(top->lchild!=NULL)
            {
    
    
                q.push(top->lchild);
            }
            if(top->rchild!=NULL)
            {
    
    
                q.push(top->rchild);
            }
                q.pop();
        }
    }
}

int n;

int main()
{
    
    
    cin >> n;
    for(int i=0; i<n; i++)
    {
    
    
        cin >> In[i];
    }
    for(int i=0; i<n; i++)
    {
    
    
        cin >> Pre[i];
    }
    node *root=create(0,n-1,0,n-1);
    layer(root);
    for(int i=0; i<cigar.size(); i++)
    {
    
    
        if(i!=0)
            cout << " ";
        cout << cigar[i];
    }
    return 0;
}

7-4

#include<iostream>
#include<vector>
using namespace std;

const int maxn=1004;
const int INF=100000000;

int n,m;

struct Edge      //对结构进行初始化,然后设置结构体,注意形式
{
    
    
    int v,score,daijinquan;
    Edge(int _v, int _score, int _daijinquan):v(_v),score(_score),daijinquan(_daijinquan){
    
    };
};

vector<Edge> graph[maxn];  //设置一个结构类型的二维数组

int in[maxn];   //in表示每个点的入度值

int pre[maxn];      //pre表示每个结点的前驱结点

void Dijkstra()   //迪杰斯特拉算法,寻找最短路径和最大边权
{
    
    
    int visited[maxn];
    int dis_score[maxn];
    int dis_daijinquan[maxn];
    fill(visited,visited+maxn,false);
    fill(dis_score,dis_score+maxn,INF);
    fill(dis_daijinquan,dis_daijinquan+maxn,0);  //以上代码像往常一样,进行初始化

    for(Edge t:graph[n])  //此for循环表示在n结点下的若干个子节点 相当于 for(int i=0; i<graph[n].size(); i++)  graph[n][i].v
    {
    
    
        dis_score[t.v]=dis_daijinquan[t.v]=0;
        pre[t.v]=n;   //设置他下面的所有前驱结点为n
    }

    for(int k=0; k<n; k++)
    {
    
    
        int min_node=n;
        int min_dis=INF;

        for(int i=0; i<n; i++)   //找到当前最小结点同时daijinquan最大的结点 min_node
        {
    
    
            if(visited[i]==true)
                continue;
            if(min_dis>dis_score[i])
            {
    
    
                min_dis=dis_score[i];
                min_node=i;
            }
            else if(min_dis==dis_score[i])
            {
    
    
                if(dis_daijinquan[min_node]<dis_daijinquan[i])
                {
    
    
                    min_node=i;
                }
            }
        }

        if(min_node==n)
            break;

        //按照以往的迪杰斯特拉算法,其实min_node下的所有下标相当于 我们之前的u  e.v相当于之前的v
        visited[min_node]=true;  //对找到的结点进行标记

        for(Edge e:graph[min_node])  //要找到最短路径,e表示 下标为min_node下的所有 结点 相当于从min_node的这个结点岔开,后面有很多的结点,从中选择最小的
        {
    
    
            if(e.score+min_dis<dis_score[e.v])  //找出最短路径
            {
    
    
                pre[e.v]=min_node;  //将e.v的前驱结点设置为min_node
                dis_score[e.v]=e.score+min_dis;
                dis_daijinquan[e.v]=e.daijinquan+dis_daijinquan[min_node];
            }
            else if(e.score+min_dis==dis_score[e.v])
            {
    
    
                if(e.daijinquan+dis_daijinquan[min_node]>dis_daijinquan[e.v])   //e.daijinquan表示如果走u所能获得的钱
                {
    
    
                    pre[e.v]=min_node; //将pre[e.v]的前驱结点设置为min_node
                    dis_daijinquan[e.v]=e.daijinquan+dis_daijinquan[min_node];
                }
            }
        }
    }
}

void consist()   //无环图
{
    
    
    printf("Okay.\n");  //无环图,输出Okay
    Dijkstra();
    int k;
    cin >> k;
    for(int i=0; i<k; i++)
    {
    
    
        int ant;
        cin >> ant;
        if(pre[ant]==n) //在迪杰斯特拉算法中已经将所有入度为0的前驱结点设置n,如果经过迪杰斯特拉算法算法之后,某个点的前驱结点还是n,则表示该点入度为0,直接访问该点
            printf("You may take test %d directly.\n",ant);
        else   //上面通过迪杰斯特拉算法已经得到从入度出发,到每个点的最短路径
        {
    
    
            vector<int> path;
            while(ant!=n)    //pre数组存放的是前驱结点,由于前驱结点的初始值设置为n,所以用n来判断循环
            {
    
    
                path.push_back(ant);        //将该结点放到path,注意是从后向前,此时所有存入path的值都是倒着的
                ant=pre[ant];   //ant访问他的前驱结点
            }
            int l=path.size();
            printf("%d",path[l-1]);
            for(int j=l-2; j>=0; j--)  //倒着输出
            {
    
    
                printf("->%d",path[j]);
            }
            printf("\n");
        }
    }
}

void not_consist()   //有环图
{
    
    
    printf("Impossible.\n");
    int k;
    cin >> k;
    for(int i=0; i<k; i++)
    {
    
    
        int ans;
        cin >> ans;
        if(in[ans]==0)   //如果某个点前驱为0,表示没有可以到达该点的点,当然是直接访问
        {
    
    
            printf("You may take test %d directly.\n",ans);
        }
        else  //否则,如果前驱不为0,说明该点在环内,则输出Error
        {
    
    
            printf("Error.\n");
        }
    }
}

bool choice()
{
    
    
    /*
        通过拓扑排序来判断是否有环?
        1.双层for,第一层for是遍历所有界点 第二层for是知道当前入度为0的点
        2.如果node==n,表示有环;标记该点已经被访问过
        3.从刚才所找到的入度为0的点出发,将从他出发所能都到达的其他结点的入度减少1
        4.最后遍历,如果该图中所有点的入度为0,表示五环则返回true 否则,有环返回false
    */
    int visited[maxn]={
    
    false};
    for(int i=0; i<n; i++)
    {
    
    
        int node=0;
        for(; node<n; node++)
        {
    
    
            if(!visited[node] && in[node]==0)
            {
    
    
                break;
            }
        }
        if(node==n)
            break;
        visited[node]=true;
        for(Edge t:graph[node])
        {
    
    
            in[t.v]--;
        }
    }
    int num=0;
    for(int i=0; i<n; i++)
    {
    
    
        if(in[i]==0)  //对于无环图而言,在上面已经将所有的点的入度减为0了。对于有环图而言,比如有的点的入度没有减为0
            num++;
    }
    if(num==n)
        return true;   //无环路
    else
        return false;  //有环图
}


int main()
{
    
    
    cin >> n >> m;
    int temp1,temp2,temp3,temp4;
    for(int i=0; i<m; i++)
    {
    
    
        cin >> temp1 >> temp2 >> temp3 >> temp4;
        graph[temp1].push_back(Edge(temp2,temp3,temp4));
        in[temp2]++;
    }
    for(int i=0; i<n; i++)
    {
    
    
        if(in[i]==0)
        {
    
    
            graph[n].push_back(Edge(i,0,0));
        }
    }
    if(choice())
    {
    
    
        consist();
    }
    else
    {
    
    
        not_consist();
    }
}

猜你喜欢

转载自blog.csdn.net/wsfhdhjs/article/details/109342025