第一届中兴捧月算法大赛迪杰斯特拉派解决方案

迪杰斯特拉派初赛赛题

最强大脑中的收官蜂巢迷宫变态级挑战,相信大家都叹为观止!最强大脑收官战打响后,收视率节节攀升,就连蚁后也不时出题难为一下她的子民们。在动物世界中,称得上活地图的,除了蜜蜂,蚂蚁当仁不让。在复杂多变的蚁巢中, 蚂蚁总是能以最快、最高效的方式游历在各个储藏间(存储食物)。今天,她看完最新一期节目,又发布了一项新任务:小蚁同学,我需要玉米库的玉米,再要配点水果,去帮我找来吧。小蚁正准备出发,蚁后又说:哎呀,回来,我还没说完呢,还有若干要求如下:
1.小蚁同学,你需要尽可能以最少的花费拿到食物(附件图中路线上的数值表示每两个储物间的花费);
2.小蚁同学,你最多只能经过9个储藏间拿到食物(包含起止两个节点,多次通过同一节点按重复次数计算);
3.小蚁同学,你必须经过玉米间,水果间(附件图中标绿色节点);
4.别忘了,食蚁兽也在路上活动呢,一旦与食蚁兽相遇,性命危矣!不过小蚁微信群公告已经公布了敌人信息(附件图中标红色路段);
5.最后,千万别忘了,还有两段路是必须经过的,那里有我准备的神秘礼物等着你呢(附件图中标绿色路段)。
这下小蚁犯难了,这和它们平时找食物的集体活动规则不一样嘛,看来这次需要单独行动了。要怎么选路呢?小蚁经过一番苦思冥想,稿纸堆了一摞,啊,终于找到了!亲爱的同学们,你们能否也设计一种通用的路径搜索算法,来应对各种搜索限制条件,找到一条最优路径,顺利完成蚁后布置的任务呢?
注:
1、蚁巢,有若干个储藏间,储藏间之间有诸多路可以到达;
2、节点本身通行无花费;
3、该图为无向图,可以正反两方向通行,两方向都会计费,并且花费相同;
4、起止节点分别为附件图中S点和E点。
5、最优路径:即满足限制条件的路径。

图片附在代码下面了,我的解决方案是对整个图进行一个限制路径的dij,用一个set来判断特殊点的个数,之后对特殊情况进行判断一下就行了。这个解法主要的优点是通用,的确牺牲了一下次优解的情况,只有70分,没拿到区域优胜有点可惜。顺便帮助队友拿到数模校赛一等奖(题目一样)

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxnum = 100;
const int maxint = 999999;


int dist[maxnum];         //initialize with maxint
int prev[maxnum];
int c[maxnum][maxnum];   //initialize with maxint
int n, line;             // 图的结点数和路径数
set<int> sp_nodes;
bool sp_edge[maxnum][maxnum];
// n -- n nodes
// v -- the source node
// dist[] -- the distance from the ith node to the source node
// prev[] -- the previous node of the ith node
// c[][] -- every two nodes' distance
inline long long fac(int n)
{
    int res=1;
    while(n!=0)
    {
        res*=n;
        n--;
    }
    return res;
}
void Dijkstra_modify(int n, int v)
{
    bool s[maxnum];
    for(int i=0; i<n; i++)
    {
        dist[i] = maxint;
    }

    for(int i=0; i<n; ++i)
    {
        dist[i] = c[v][i];
        s[i] = 0;                         
        if(dist[i] == maxint)
            prev[i] = 0;
        else
            prev[i] = v;
    }

    dist[v] = 0;
    s[v] = 1;

    for(int i=1; i<n; ++i)
    {
        int tmp = maxint;
        int u = v;

        for(int j=0; j<n; ++j)
        {
            if((!s[j]) && dist[j]<tmp)
            {
                u = j;              
                tmp = dist[j];
            }
            // let the special nodes and the current point's edge minimum
            // but if there are mutiple of special node ?
        }

        s[u] = 1;
        // refresh extend
        // no need to change
        for(int j=0; j<n; ++j)
            if((!s[j]) && c[u][j]<maxint)
            {
                int newdist = dist[u] + c[u][j];
                if(newdist < dist[j])
                {
                    dist[j] = newdist;
                    prev[j] = u;
                }
            }
    }
}
void print(int x,int s)
{
    stack<int>q;
    int flag(s);
    while(x!=s)
    {
        q.push(x);
        x=prev[x];
    }
    q.push(s);
    while(q.empty()==0)
    {
        cout<<q.top()<<"->";
        q.pop();
    }
    cout<<"\n";
}

int main()
{
    freopen("graph_in.txt","r",stdin);
    freopen("graph_out.txt","w",stdout);
    int t1= 0,t2=0,t3=0;
    int st_node,tm_node;
    cin>>n>>line;
    for(int i=0; i<=n; i++)
    {
        dist[i]=maxint;
        for(int j=0; j<=n; j++)
        {
            c[i][j]=maxint;
        }
    }
    for(int i=0; i<line; i++)
    {
        cin>>t1>>t2>>t3;
        c[t1][t2] = c[t2][t1] = t3;
    }
    //
    cin>>st_node>>tm_node;
    for(int i=0; i<2; i++)
    {
        cin>>t1;
        sp_nodes.insert(t1);
    }
    for(int i=0; i<2; i++)
    {
        cin>>t1>>t2;
        sp_nodes.insert(t1);
        sp_nodes.insert(t2);
        sp_edge[t1][t2] = sp_edge[t2][t1] = true;

    }
    //edge that unreachable
    cin>>t1>>t2;
    c[t1][t2] = c[t2][t1] = maxint;
    //begin
    vector<int> path,path_p;
    vector<int> sp_nodes_p;
    int cnt=0;
    int ans=maxint;
    int cnt_nodes=0;
    for(set<int>::iterator sit = sp_nodes.begin(); sit!=sp_nodes.end(); sit++)
    {

        sp_nodes_p.push_back(*sit);
    }
    int times=fac(sp_nodes.size());
    for(int i=0; i<times; i++)
    {
        //generate the permutation
        next_permutation(sp_nodes_p.begin(),sp_nodes_p.end());


        path_p.clear();

        vector<int>::iterator it = sp_nodes_p.begin();
        Dijkstra_modify(n,st_node);
        cnt += dist[*it];
        path.push_back(*it);
        //cout<<"st: "<<cnt<<endl;
        bool sp_edge_p[maxnum][maxnum];
        memcpy(sp_edge_p,sp_edge,sizeof(sp_edge_p));

        bool flag = true;

        while(1)
        {

            int tmp=*it;
            it++;
            if(it==sp_nodes_p.end())
            {
                break;
            }
            if(sp_edge_p[tmp][*it])
            {
                //cout<<"hit : "<<tmp<<"->"<<*it<<" ";
                sp_edge_p[*it][tmp] = false;
                //refresh the temp
                cnt += c[tmp][*it];
                //cout<<c[tmp][*it]<<endl;
                path_p.push_back(tmp);
                path_p.push_back(*it);
            }
            else
            {
                for(int j=0; j<n; j++)
                {
                    if(sp_edge_p[tmp][j])
                    {
                        flag = false;
                        break;
                    }
                }
                if(!flag)
                {
                    break;
                }
                Dijkstra_modify(n,tmp);
                cnt += dist[*it];
                //refresh the temp
                //cout<<"short : "<<tmp<<"->"<<*it<<" : ";
                //print(*it,tmp);
                stack<int> q;
                int tmp2=*it;
                while(tmp2!=tmp)
                {
                    q.push(tmp2);
                    tmp2=prev[tmp2];
                }
                while(q.empty()==0)
                {
                    path_p.push_back(q.top());
                    q.pop();
                }
                //cout<<dist[*it]<<endl;
            }
        }
        if(!flag)
        {
            //cout<<"pass"<<endl;
            cnt=0;
            continue;
        }

        int e=sp_nodes_p[sp_nodes_p.size()-1];
        Dijkstra_modify(n,e);
        cnt+=dist[tm_node];
        //cout<<"Path :";
        int judge=st_node;

        //cout<<tm_node<<endl;
        //cout<<"tm :"<<dist[tm_node]<<endl;
        if(ans > cnt)
        {
            path.clear();
            ans = cnt;
            for(vector<int>::iterator pit =path_p.begin(); pit!=path_p.end(); pit++)
            {
                if(judge == *pit) continue;
                judge=*pit;
                path.push_back(*pit);
            }
            cnt_nodes=path.size();
        }
        cnt=0;
    }
    cout<<"distance :"<<ans<<endl;
    int judge = st_node;
    cout<<"path :"<<st_node<<"->";
    for(int i=0; i<cnt_nodes; i++)
    {
        if(judge == path[i]) continue;
        cout<<path[i]<<"->";
        judge=path[i];
    }
    cout<<tm_node<<endl;
    if(cnt_nodes>6)
    {
        cout<<"No optimal solution"<<endl;
    }
    else
    {
        cout<<"The optimal solution:"<<endl;
    }
    cout<<"number of nodes :"<<cnt_nodes+2<<endl;
    return 0;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值