pat甲级真题分裂-迪杰斯特拉

本文探讨了如何使用拓扑排序和迪杰斯特拉算法解决一个问题,涉及超级源点的概念、专业能力测试的路径选择以及无环图与有环图中一致性检查。通过实例展示了如何利用拓扑图和Dijkstra's Algorithm进行路径规划,同时考虑了代金券和考试分数的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拓扑图+dijskra+超级源点

7-4 Professional Ability Test (30 分)



#include<bits/stdc++.h>
using namespace std;

const int maxn=1011;

int N,M;

int score[maxn][maxn],voucher[maxn][maxn];

int inDegree[maxn],query[maxn];

vector<int> Adj[maxn];

unordered_set<int> zeroDegree;

bool topologicalOrder()
{
    queue<int> q;
    for(int i=0; i<N; i++)
        if(inDegree[i]==0)
            q.push(i);

    int num=0;
    while(q.size())
    {
        int t=q.front();
        q.pop();

        num++;

        for(int i=0; i<Adj[t].size(); i++)
        {
            int v=Adj[t][i];

            inDegree[v]--;

            if(inDegree[v]==0)
                q.push(v);
        }
    }

    return num==N;

}

int dis[maxn],money[maxn],pre[maxn];

bool visited[maxn];

void Dijsktra(int start)
{
    memset(dis,0x3f,sizeof dis);
    dis[start]=0,money[start]=0;

    for(int i=0; i<N+1; i++)
    {
        int t=-1;
        for(int j=0; j<N+1; j++)
            if(!visited[j] && (t==-1 || dis[j]<dis[t]))
                t=j;

        visited[t]=true;

        for(int j=0;j<Adj[t].size();j++)
        {
            int v = Adj[t][j];      //v是下一个要走的节点
            if(!visited[v])
            {
                if(dis[v]>dis[t]+score[t][v])
                {
                    // 当前路径更短
                    pre[v] = t;
                    dis[v] = dis[t]+score[t][v];
                    money[v] = money[t] + voucher[t][v];
                } else if(dis[v]==dis[t]+score[t][v]&&money[v]<money[t]+voucher[t][v]){
                    // 需要考试的分数一样,但是获得的代金券更多
                    pre[v] = t;
                    money[v] = money[t] + voucher[t][v];
                }
            }
        }
    }
}

void Dfs(int u)
{
    if(pre[u]==N)
    {
        printf("%d",u);
        return ;
    }
    Dfs(pre[u]);
    printf("->%d",u);
}

void consistent(int query[],int K)
{
    Dijsktra(N);
    for(int i=0; i<K; i++)
    {
        if(zeroDegree.find(query[i])!=zeroDegree.end())
        {
            printf("You may take test %d directly.\n",query[i]);
        }
        else
        {
            Dfs(query[i]);
            cout << endl;
        }
    }
}

void notConsistent(int query[],int K)
{
    for(int i=0; i<K; i++)
    {
        if(zeroDegree.find(query[i])!=zeroDegree.end())
        {
            printf("You may take test %d directly.\n",query[i]);
        }
        else
            cout << "Error" << endl;
    }
}

int main()
{
    cin >> N >> M;
    for(int i=0; i<M; i++)
    {
        int a,b,c,d;
        cin >> a >> b >> c >> d;
        score[a][b]=c;
        voucher[a][b]=d;
        inDegree[b]++;
        Adj[a].push_back(b);
    }

    for(int i=0; i<N; i++)
    {
        if(inDegree[i]==0)
        {
            Adj[N].push_back(i);
            zeroDegree.insert(i);
        }
    }

    bool isOk = topologicalOrder();

    int K;
    cin >> K;
    for(int i=0; i<K; i++)
        cin >> query[i];

    if(isOk)        //无环图
    {
        printf("Okay.\n");
        consistent(query,K);
    }
    else        //有环图
    {
        printf("Impossible.\n");
        notConsistent(query,K);
    }

}



判断给出的路径是否为迪杰斯特拉路径

7-4 Dijkstra Sequence (30 分)

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

typedef pair<int,int> PII;
const int N = 1010, M = 2e5 + 10;
int T, n, m;
int h[N], e[M], ne[M], w[M], idx;
int seq[N];
int dist[N];
bool st[N];

void add(int a, int b, int c) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dijkstra()         //堆优化版的dijkstra
{
    priority_queue<PII, vector<PII>, greater<PII>> heap;        //设置一个优先队列
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    dist[seq[0]] = 0;
    heap.push({0, seq[0]});
    while (!heap.empty())
    {
        PII t = heap.top();
        heap.pop();

        int ver = t.second;
        if (st[ver]) continue;
        st[ver] = true;

        for (int i = h[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j], j});
            }
        }
    }

}
int main()
{
    memset(h, -1, sizeof h);
    scanf("%d%d", &n, &m);

    while (m--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b,&c);
        add(a, b, c), add(b, a, c);
    }

    scanf("%d", &T);
    while (T--)
    {
        for (int i = 0; i < n; ++i)
            scanf("%d", &seq[i]);

        dijkstra();
        bool flag = true;
        for (int i = 1; i < n; ++i)             //最后判断这条路径是否为dijkstra路径,如果当前这个点的距离小于前一个点,直接是false
        {
            if (dist[seq[i]] < dist[seq[i - 1]])
            {
                flag = false;
                break;
            }
        }
        if (flag)
            puts("Yes");
        else
            puts("No");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值