首次手撸迪杰斯特拉算法+对于特定情况下的调整优化+DFS(1003-Emergency)

题目内容

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

翻译

作为一个城市的紧急救援队长,你会得到一张你所在国家的特殊地图。这张地图显示了几个分散的城市,由一些道路连接起来。每个城市的救援队伍数量和任何两个城市之间的每条道路的长度都在地图上标出。当你接到来自其他城市的紧急呼叫时,你的工作是带领你的人尽快赶到那个地方,与此同时,召集尽可能多的人在路上。

Input Specification(输入格式):

在这里插入图片描述

说明(有道不给翻译。。。)

就是第一行四个数分别是节点数,行数,起点,终点。
第二行为各个城市的救护人员的人数
之后m行为公路的起点城市,终点城市,路程长度。
最后输出要求为:起点到终点的最短路径条数和最短路径中最多能获得的救护人员人数

Sample Input(样例):

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

Sample Output(正确输出):

2 4

解题思路

这个可以说是,相当大的一道题了,首先,我们要一个点到另一个点的最短距离,而谈到这一点,迪杰斯特拉算法自然是第一选择,说来也是惭愧,我作为一名计算机本科生,上了三年了,之前遇到用迪杰斯特拉算法的地方很多,但是从来都是直接拿来主义,网上copy一个接口改改就直接用了,这回也算是心血来潮,想要手撸一回。

其实迪杰斯特拉算法的话,初次接触可能会觉得,这个很难很绕,不过我虽然没有自己手写过,但是理论我还是学的很透彻的,所以第一次手撸其实还算是比较顺利。

主要流程:首先,用map<int,vector<(int)>>将每一个节点相联的节点存储起来,当然了,我们直接用数组也可以,不过这样用起来我更顺手一些,然后,设置一个visit数组,第一次的时候,只对起点设置为1,说明我们已经取了节点,这个时候节点到节点的数据为0,然后接下来,我们取起点的所有邻居节点中最近的那个为被访问的节点,visit设置为1,然后,我们看这两个节点所能够到的节点,从中找到一个最近的为被访问的,visit设置为1,然后看这三个节点。。。

大概的一个迪杰斯特拉算法的流程就是这样的了,不过我们还需要注意就是对于一个节点被选中了,他是从哪一个节点来的还是不同的,就比如我起点选中,那么路径本身就是距离,但是如果被其他的节点选中,那么到那个节点的距离也是要考虑的。所以我们又设置了juli数组用来存储我们到每一个选中节点的距离。

这样一来,我们的迪杰斯特拉算法就算是完成了。

此时,我们回过头来看,我们的题目要求中还要我们选择一个最短并且能够得到最多救援人员的路径,也就是途径的节点的权值和要最小的,那么我们就需要另起一个数组geted(别问,问就是随性取名法),用来记录每一个节点到这里能有多少救护人员,初始化起点,然后后续就是选中的节点本身+链接的那个节点的geted的数据就可以了(类似前缀和)。

这样看起来,我们似乎可以直接提交了,但是很遗憾,我们还是忽略了一点,导致我还是有一些样例错了,那就是他要我们给出的是最短路径数目,但是我们知道,我们这个思路找到最短之后就返回了,如果要改的话,动的代码会很多,所以我就灵机一动,改用DFS来解决这个问题。

我们有起点,终点,要的路径权值和,有图,直接DFS找长度和当前节点都达标的路径的种类就行,这个相比前面,我可太熟练了,这里也就不多说了。

最后,成功AC,也算是一道收货不少的题目了。

最后,上代码(最后附两个测试样例)

这里注释掉的都是调试的时候用到的一些输出,如果想细扣的话可以解开看一下。


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

int juli[500]={0};
int geted[500]={0};
int zoufa=0;
map<int,vector<int>> ans;

int daan=0;

int visit2[500]={0};
void dfs(map<int,vector<int>> mp,int len,int tu[500][500],int zou,int now,int zhong)
{
    if(zou==len&&now==zhong){
        zoufa++;
        return;
    }
    if(zou>len){
        return;
    }
    for(int i=0;i<mp[now].size();i++){
        if(visit2[mp[now][i]]==0){
            visit2[mp[now][i]]=1;
            dfs(mp,len,tu,zou+tu[now][mp[now][i]],mp[now][i],zhong);
            visit2[mp[now][i]]=0;
        }
    }
}

int djstl(map<int,vector<int>> mp,int visit[500],int tu[500][500],int qi,int zhong,int n)
{
    set<int> havedone;
    while(visit[zhong]==0)
    {
        int num;int lengths=INT_MAX;int from;int ren;
        for(int i=0;i<n;i++){
            if(visit[i]==1){
                for(int j=0;j<mp[i].size();j++){
                    if((tu[i][mp[i][j]]+juli[i]<lengths||(tu[i][mp[i][j]]+juli[i]==lengths&&geted[i]>=ren))&&visit[mp[i][j]]!=1){
                        if(tu[i][mp[i][j]]+juli[i]<lengths){
                            daan=1;
                        }
                        else{
                            daan++;
                        }
                        lengths=tu[i][mp[i][j]]+juli[i];
                        num=mp[i][j];
                        from=i;
                        ren=geted[i];
                    }
                }
            }
        }
        visit[num]=1;
        geted[num]+=geted[from];
        juli[num]=lengths;
//
//        for(int i=0;i<ans[from].size();i++){
//            ans[num].push_back(ans[from][i]);
//        }
//
//        ans[num].push_back(num);
        if(num==zhong){
//            for(int i=0;i<n;i++){
//                cout<<juli[i]<<" "<<geted[i]<<endl;
//            }
            dfs(mp,lengths,tu,0,qi,zhong);
            cout<<zoufa<<" "<<geted[num]<<endl;
            return lengths;
        }
    }

}

int main()
{
    int m,n;
    map<int,vector<int>> mp;
    int qi;
    int zhong;
    int tu[500][500]={0};
    cin>>n>>m>>qi>>zhong;
    for(int i=0;i<n;i++){
        cin>>geted[i];
        vector<int> mid;
        mp.insert(pair<int,vector<int>>(i,mid));
        ans.insert(pair<int,vector<int>>(i,mid));
    }

//    cout<<"from?to?len?"<<endl;

    for(int i=0;i<m;i++){
        int from,to,len;
        cin>>from>>to>>len;
        mp[from].push_back(to);
        mp[to].push_back(from);
        tu[from][to]=len;tu[to][from]=len;
    }

    int visit[500]={0};

    visit[qi]=1;visit2[qi]=1;
    ans[qi].push_back(qi);
    if(qi!=zhong){
        djstl(mp,visit,tu,qi,zhong,n);
    }
    else{
        cout<<"1"<<" "<<geted[qi]<<endl;
    }
//    cout<<djstl(mp,visit,tu,qi,zhong,n)<<endl;;

//    for(map<int,vector<int>>::iterator it=ans.begin();it!=ans.end();it++){
//        if(it->second.size()!=0){
//            for(int i=0;i<it->second.size();i++){
//                cout<<it->second[i]<<" ";
//            }
//            cout<<endl;
//        }
//    }

    return 0;
}



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

//结果:2 4

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

//结果:2,4

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值