XiyouLinux兴趣小组免试题——level 5

感谢出免试题过程中帮助我的各位学长以及提供思路的同学。

很荣幸成为免试题出题人之一,这次出题也算是对自己的一种磨练。第五关作为整个免试题的最后一关,主要考察点是算法的图论方面。接下来详细介绍一下第五关的通关攻略lol。

题目链接:level 5

假设你现在已经通过前四关来到了最后一关,首先映入眼帘的是一些星球的连线。

相信有点图论基础的同学此时心里会大概有个方向了吧,页面上有个提交按钮还有一个start:1 end:4的提示告诉你起始点为1目标点为4。页面上暂时没有什么其他的有效信息,好在点比较少,我们可以先一个一个试一下。

对于给定的起始点和目标点来说,我们有以下四种路径:
1:1->2->4
2:1->3->4
3:1->5->4
4:1->6->4
这四条路径权值和分别为:
1->2->4 :2 + 3 = 5
1->3->4 :3 + 4 = 7
1->5->4 :4 + 5 = 9
1->6->4 :5 + 6 = 11

我们分别尝试这四条路径,发现提交1->3->4这条路径时页面跳转了,进入了第五关的第二个页面。

页面二

好吧,我相信在看到第二个页面的时候很多同学的内心是拒绝的O。。。我的内心也是拒绝的。。。然而再怎么吐槽这个图我也是硬着头皮画的你们也得硬着头皮做。。。ORZ

clock

一开始拿到这个图可能会有些头大,会发现有个残忍的倒计时,但这个时候需要你们理清思路回顾以下上一个页面。在上一个页面中,我们选择1->3->4 这条路径后进入到这个页面,根据上面每条路径权值和的分析,我们发现1->3->4 是所有路径中权值和第二小的的路径。思考到这里,第五关的通关规则就很清楚了,需要你找到从起始点到目标点的次短路径

但是这么多星球,这么多连线,自己画出来十分的麻烦,这时我们可以延续前四关的优良传统——审查元素。

结点信息

这么明显的结点信息我想瞎子都能看到吧。。。赶紧先保存下来。

大概看了看,能够发现总共有50个点,97条边,每条边的权值为分数。
现在图信息有了,通关规则也有了,剩下的就是解题了。倒计时为30s,这意味着你肯定不能手动计算,还是乖乖谷歌下次短路算法吧。我们先假设你学会了次短路算法,假设你也写好了代码,假设你也得出了答案。。

#include 
#include 
#include 
#include 
#include 
#define N 205
#define MAX 0x03fffffff
using namespace std;
double Metrix[N][N];
double dist[N];
int vist[N];
int path[N];

struct edge
{
    int s,t;
    double cost;
}E[N];
/*
   void OutPath(int s,int t,int NV)//输出路径
   {
   for(int i=1;i<=NV;i++)
   {
   }
   int u=s,v=t;
   while(v!=s)
   {
   v=path[v];
   }
   }
   */

int Dijkstra(int s,int t,int NV)
{
    int u=s,v=t;
    for(int i=1;i<=NV;i++)
    {
        dist[i]=MAX;
        vist[i]=0;
    }
    for(int i=1;i<=NV;i++)
    {
        path[i]=s;
    }
    dist[u]=0;

    for(int i=1;i<=NV;i++)
    {
        double min_value = MAX;
        for(int j=1;j<=NV;j++)
        {
            if(vist[j]==0&&dist[j]1;
        for(int j=1;j<=NV;j++)
        {
            if(vist[j]==0&&dist[u]+Metrix[u][j]if(fabs(dist[t]-MAX) < 0.000001)return -1;
    return 10;
}

void SP2th(int s,int t,int NV)//NV为节点数
{
    int flag=Dijkstra(s,t,NV);//求最短路
    printf("%lf ", dist[t]);
    if(flag==-1)
    {
        printf("0");
    }
    else
    {
        float min_SP=MAX;
        int u=s,v=t,arcNum=0;
        while(v!=u)//保存最短路到E[i]
        {
            E[arcNum].s=v;
            E[arcNum].t=path[v];
            E[arcNum].cost=Metrix[v][path[v]];
            arcNum++;
            v=path[v];
        }

        for(int i=0;i//删除E[i]
            u=E[i].s;
            v=E[i].t;
            Metrix[u][v]=Metrix[v][u]=MAX;
            flag=Dijkstra(s,t,NV);//重新计算最短路
           // printf("  %lf-=-=\n", dist[t]);
            if(flag==-1)
            {
                printf("0");
            }
            else
            {
                //OutPath(s,t,NV);
                if(min_SP>dist[t])min_SP=dist[t];
            }
            Metrix[u][v]=Metrix[v][u]=E[i].cost;

            int u = s, v = t;
            while(v != u){
                printf("%d->", v);
                v = path[v];
            }


            printf("%d  %lf\n",s, dist[t]);

        }
        printf("%lf",min_SP);
    }
}
int main(int argc, char * argv[])
{
    int m,n;//n为节点数,m为边数
    int ss = 0;
    int tt = 0;
    ss= atoi(argv[1]);
    tt = atoi(argv[2]);
    freopen("./CASE.txt", "r", stdin);
    cin >> n >> m;
    int s,t;
    int aa, bb;
    double c = 0.0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j)
            {
                Metrix[i][j]=MAX;
            }
            else
            {
                Metrix[i][j]=MAX;
                Metrix[j][i]=MAX;
            }
        }
    }
    for(int i=0;i//每条路的代价
    {
        cin >> s >> t >> aa >> bb;
        c = aa /(bb * 1.0);


        if(c<=Metrix[t][s])
        {
            Metrix[s][t]=Metrix[t][s]=c;
        }
    }

    SP2th(ss,tt,n);////求s->t的次短路

    return 0;
}

提交

30秒的时间真的是有点紧,不过如果你是用程序的话还是可以来得及的,我们提交下试试

结束

看样子是过咯~

结束的话:
通关只是目的之一,第五关作为最后一关并不是挡住所有做题的人才高兴,更重要的是希望大家能够在做题的过程中学到有用的知识,如果想要学习次短路算法,建议从学习最短路算法起步。

你可能感兴趣的:(Algorithm)