华为机试题——朋友圈转发信息

没去机试,题目在这位仁兄的博客里有http://blog.csdn.net/xvwentao89/article/details/38560503

渣渣还没想到简单的模型,只有一个复杂些的思路:

(1)因为要保证每个人都在最短的时间内收到消息,所以到达每个人的消息传递路径必须是最短路径,由此我们可以将朋友圈的消息传递按距离分成几层,渣渣下面的代码用的spfa算最短路,然后再将最短路长度相同的人分到同一组,写完之后想想其实直接一次BFS就可以将两者完成了,复杂度还低些……

(2)分层之后,只要保证每一层的所有人都会被上一层通知到即可,由此可以逐层求出两层之间需要转发的最小次数,渣渣目前用的暴搜,要是能用DP就好了,唉……

由于题目中没有告知输入规模、标号范围神马的,只是保证了图的连通性,所以我也就没有假设所有人按1~N标号,只假设所有人都被唯一的正整数标识

#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
/*
    suppose every person has been labeled by a unique positive number
*/
int sponsor;                //the news sender
map<int, set<int> > friends;//relationship graph, use set to avoid repeated edges

map<int, int> dis;          //each person's shortest distance to sponsor
queue<int> q;               //used in spfa
map<int, bool> inq;         //used in spfa

vector<vector<int> > level; //group people with same distance to sponsor

int fromLevel, forwards;    //used in DFS to find minimum forwards needed between fromLevel to fromLevel + 1
map<int,int> toldBy;        //used in DFS to mind each person's teller in previous level

void input()
{
    string line;
    int x, y;
//input sender
    getline(cin, line);
    cin >> sponsor;
    getline(cin, line);
//input relationship
    getline(cin, line);
    while(getline(cin, line), line != "End"){
        sscanf(line.c_str(), "%d,%d", &x, &y);//undirected graph
        friends[x].insert(y);
        friends[y].insert(x);
    }
}
void spfa()
{
//initialize 
    for(map<int, set<int> >::iterator iter = friends.begin(), eter = friends.end(); 
        iter != eter; 
        ++iter){
        dis[iter->first] = friends.size();
        inq[iter->first] = false;
    }
    dis[sponsor] = 0;
    q.push(sponsor);
    inq[sponsor] = true;
//relax process
    set<int>::iterator iter, eter;
    while(!q.empty()){
        int x = q.front();
        q.pop();
        inq[x] = false;
        iter = friends[x].begin(); eter = friends[x].end();
        for(; iter != eter; ++iter){
            int y = *iter;
            if(dis[y] > dis[x] + 1){
                dis[y] = dis[x] + 1;
                if(!inq[y]){
                    q.push(y);
                    inq[y] = true;
                }
            }
        }
    }
}
void separate()
{
    map<int, int>::iterator iter = dis.begin(), eter = dis.end();
//there are maxDistance + 1 levels
    level.resize(dis.rbegin()->second + 1);
    for(; iter != eter; ++iter){
        level[iter->second].push_back(iter->first);
    }
}
bool allKnown()
{
    map<int,int>::iterator iter = toldBy.begin(), eter = toldBy.end();
    for(; iter != eter; ++iter){
        if(0 == iter->second) return false;
    }
    return true;
}
void post(int teller, set<int>& peer)
{
    set<int>::iterator iter = peer.begin(), eter = peer.end();
    map<int,int>::iterator ater = toldBy.begin(), bter = toldBy.end();
    for(; iter != eter; ++iter){
        ater = toldBy.find(*iter);//*iter might not in this level
        if(ater != bter && ater->second == 0) ater->second = teller;
    }
}
void undo(int teller, set<int>& peer)
{
    set<int>::iterator iter = peer.begin(), eter = peer.end();
    map<int,int>::iterator ater = toldBy.begin(), bter = toldBy.end();
    for(; iter != eter; ++iter){
        ater = toldBy.find(*iter);//*iter might not in this level
        if(ater != bter && ater->second == teller) ater->second = 0;
    }
}
void dfs(int index, int doPost)
{
    if(index < 0){
        if(allKnown() && doPost < forwards) forwards = doPost;
        return;
    }
//if this person do not make a forward
    dfs(index - 1, doPost);
//if this person do a forward
    post(level[fromLevel][index], friends[level[fromLevel][index]]);
    dfs(index - 1, doPost + 1);
    undo(level[fromLevel][index], friends[level[fromLevel][index]]);
}
int getMinimumForwards()
{
//because the sponsor's post does not count, we dont need to calculate forwards between level 0 and level 1
//though it is just 1, as we have only one sponsor
    int sum = 0, i = 2, n = level.size();
//find minimum forwards needed between each adjacent levels, 1->2, 2->3, ...
    for(; i < n; ++i){
    //at most each person in this level make a forward
        fromLevel = i - 1;
        forwards = level[fromLevel].size();
    //set known flags of all people in next level to be false
        toldBy.clear();
        const vector<int>& v = level[i];
        for(int j = 0, m = v.size(); j < m; ++j){
            toldBy[v[j]] = 0;//insert and set value
        }
    //DFS to find best result
        dfs(level[fromLevel].size() - 1, 0);
        sum += forwards;
    }
    return sum;
}

int main()
{
/* read input */
    input();
/* find out each person's shortest distance to sponsor */
    spfa();
/* separate each group by distance to sponsor */
    separate();
/* find out minimum forwards */
    printf("%d\n", getMinimumForwards());
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值