星球游戏题解

50分解法

由于n很小只有100,我们可以用建一个n^2的矩阵,用floyd,dijkstra或者spfa等等最短路的相关算法跑出每个点对见的最短距离,然后再判断两个点是不是一个是牛牛占领的星求,一个是牛妹占领的星球即可。时间复杂度和空间复杂度根据选择的最短路算法而不同,如果使用floyd时间复杂度为o(n^3),空间复杂度为o(n^2)。

100分解法

这里提供两种做法

1.跑min(p,q)次dijkstra算法,时间复杂度为o(nlogn*min(p,q)),空间复杂度o(n+m)

虽然p+q的值很大,但是p和q中小的值并不大,我们可以分别以p和q中少的点为起点跑最短路,然后每次跑完最短路判断这个点对应的点是否为另一个人占领的星球,如果是执行 ans=min(ans,dis[i])。 代码如下:

完善核心代码模式代码:

#define MAX 1000000001
const int maxn=100005;
int num[maxn];
int n,s;
int uss[maxn];
struct edge{int to;int cost;
 bool operator < (const edge & a) const
     {
        return cost> a.cost;
     }
};
vector<edge>g[maxn];
priority_queue<edge> vis;
void dijkstra()
{
    int i;
    for(i=1;i<=n;i++)
      num[i]=MAX;
      num[s]=0;
      vis.push((edge){s,0});
    while(!vis.empty())
    {
        edge node=vis.top();
        vis.pop();
        for(i=0;i<g[node.to].size();i++)
            if(num[g[node.to][i].to]>node.cost+g[node.to][i].cost)
                {
                   num[g[node.to][i].to]=node.cost+g[node.to][i].cost;
                   vis.push((edge){g[node.to][i].to,num[g[node.to][i].to]});
                }
    }
}
class Solution {
public:
    /**
     * 
     * @param niuniu int整型vector 牛牛占领的p个星球的编号
     * @param niumei int整型vector 牛妹占领的q个星球的编号
     * @param path int整型vector<vector<>> m条隧道,每条隧道有三个数分别是ui,vi,wi。ui,vi分别是隧道的两边星球的编号,wi是它们之间的距离
     * @param nn int整型 星球个数n
     * @return int整型
     */
    int Length(vector<int>& niuniu, vector<int>& niumei, vector<vector<int> >& path, int nn) {
        // write code here
        n=nn;
        edge tmp;
        stack<int >sta;
        if(niuniu.size()<=10)
        {
            for(int i=0;i<niuniu.size();i++)
            {
                sta.push(niuniu[i]);
            }
            for(int i=0;i<niumei.size();i++)
            {
                uss[niumei[i]]=1;
            }
        }
        else
        {
            for(int i=0;i<niuniu.size();i++)
            {
                uss[niuniu[i]]=1;
            }
            for(int i=0;i<niumei.size();i++)
            {
                sta.push(niumei[i]);
            }
        }
        for(int i=0;i<path.size();i++)
        {
            int x=path[i][0];
            tmp.to=path[i][1];
            tmp.cost=path[i][2];
            g[x].push_back(tmp);
            swap(tmp.to,x);
            g[x].push_back(tmp);
        }
        int ans=MAX;
        while(!sta.empty())
        {
            s=sta.top();
            sta.pop();
            dijkstra();
            for(int i=1;i<=n;i++)
            {
                if(uss[i])
                {
                    ans=min(ans,num[i]);
                }
            }
        }
        if(ans==MAX)ans=-1;
        return ans;
    }
};

2.只跑一次最短路的方法

当然,这道题还有更优的做法。第一个做法之所以可行是因为min(p,q)<=10,其实即使删除这个条件,这道题也是可做的,而且只需要跑一次最短路,显然时间复杂度更低,为o(nlogn),空间复杂度同为o(n+m)。具体实现方法是建立一个超级起点(这个思想有点类似于网络流),我们使这个起点向所有牛牛星建立一条权值为0的边,然后跑一次dijkstra,对于每个牛妹星执行 ans=min(ans,dis[i])即可,代码如下:

完善核心代码模式代码:

const int maxn = 200005;
const int maxm = 800005;
int n,m,s,tol,head[maxn],dis[maxn];
struct edge{int to,w,next;}g[maxm];
struct node
{
    int u,d;
    friend bool operator <(node a,node b)
    {
        return a.d>b.d;
    }
};
void add(int u,int v,int w)
{
    g[tol].to = v;
    g[tol].w = w;
    g[tol].next = head[u];
    head[u] = tol++;
}
void dijkstra(int s)
{
    for(int i = 1;i<=n;i++) dis[i] = 0x3f3f3f3f;
    dis[s] = 0;
    priority_queue<node>q;
    q.push((node){s,0});
    while(!q.empty())
    {
        node p = q.top();
        q.pop();
        int u = p.u,d = p.d;
        if(d!=dis[u]) continue;
        for(int i = head[u];i!=-1;i = g[i].next)
        {
            int v = g[i].to;
            int w = g[i].w;
            if(dis[u]+w<dis[v])
            {
                dis[v] = dis[u] + w;
                q.push((node){v,dis[v]});
            }
        }
    }
}
bool vis[maxn];
class Solution {
public:
    /**
     * 
     * @param niuniu int整型vector 牛牛占领的p个星球的编号
     * @param niumei int整型vector 牛妹占领的q个星球的编号
     * @param path int整型vector<vector<>> m条隧道,每条隧道有三个数分别是ui,vi,wi。ui,vi分别是隧道的两边星球的编号,wi是它们之间的距离
     * @param nn int整型 星球个数n
     * @return int整型
     */
    int Length(vector<int>& niuniu, vector<int>& niumei, vector<vector<int> >& path, int nn) {
        // write code here
        n=nn+1;
        memset(head,-1,sizeof(head));
        for(int i=0;i<niuniu.size();i++)
        {
            add(n,niuniu[i],0);
        }
        for(int i=0;i<niumei.size();i++)
        {
             vis[niumei[i]]=1;
        }

        for(int i=0;i<path.size();i++)
        {
            add(path[i][0],path[i][1],path[i][2]);
            add(path[i][1],path[i][0],path[i][2]);
        }
        dijkstra(n);
         int ans = 0x3f3f3f3f;
        for(int i = 1;i<=n;i++) {
            if(vis[i]) ans = min(ans,dis[i]);
        }
        if(ans==0x3f3f3f3f)ans=-1;
        return ans;
    }
};
全部评论

相关推荐

HR_丸山彩同学:你的项目描述里,系统设计讲了很多:MemCube是什么、三级存储架构怎么设计、四种遗忘策略分别是什么。这些面试的时候讲没问题,但简历上不需要这么细。 简历要突出的是影响力,不是实现细节。面试官看简历的时候想知道的是「这个项目有多大价值」,不是「这个项目具体怎么实现的」。实现细节是面试时候聊的 怎么改:技术细节可以精简为一句「采用三级存储架构+四种遗忘策略」,把省出来的篇幅用来写影响力。比如:项目有没有开源?有没有写成技术博客?有没有被别人使用过? 校园经历没有任何信息量,任何人都可以写这句话,写了等于没写。更关键的是,你投的是技术岗,校园活动经历本来就不是加分项。如果非要写,必须写出具体的数字和成果。如果你没有这些数字,那就老老实实删掉 「端到端耗时缩减30-40%」要给出确切数字和绝对值。从1000ms降到600ms是降了40%,从100ms降到60ms也是降了40%,但这两个含义完全不一样。其他也是,涉及到数据,准备好证据,口径统一,面试会问 「熟练」「熟悉」「了解」混在一起用,读起来很乱。而且「了解前端需求」最好改成「具备前后端协作经验」
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务