首页 > 试题广场 >

小团的配送团队

[编程题]小团的配送团队
  • 热度指数:2762 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

       小团是美团外卖的区域配送负责人,众所周知,外卖小哥一般都会同时配送若干单,小团在接单时希望把同一个小区的单子放在一起,然后由一名骑手统一配送。但是由于订单是叠在一起的,所以,他归类订单时只能知道新订单和已有的某个订单的小区是相同的,他觉得这样太麻烦了,所以希望你帮他写一个程序解决这个问题。

       即给出若干个形如a b的关系,表示a号订单和b号订单是同一个小区的 ,请你把同一个小区的订单按照编号顺序排序,并分行输出,优先输出最小的订单编号较小的小区订单集合。订单的编号是1n(可能存在同时出现a bb a这样的关系,也有可能出现a a这样的关系)


输入描述:

输入第一行是两个正整数n,m,表示接受的订单数量和已知的关系数量。(1<=n,m<=10000)

接下来有m行,每行两个正整数a和b,表示a号订单和b号订单属于同一个小区(1<=a,b<=n);



输出描述:

输出第一行包含一个整数x,表示这些订单共来自x个不同的小区。

接下来的输出包含x行,每行表示输出若干个订单编号,表示这些订单属于同一个小区,按照订单编号升序输出。优先输出最小的订单编号较小的小区。

示例1

输入

5 5
1 2
2 2
3 1
4 2
5 4

输出

1
1 2 3 4 5
n, order = list(map(int, input().split()))
temp = [i for i in range(n+1)]
group = dict(zip(temp, [[i] for i in range(n+1)]))
for _ in range(order):
    pair = list(map(int, input().split()))
    if temp[pair[0]] < temp[pair[1]]:
        group[temp[pair[0]]] += group[temp[pair[1]]]
        wait = temp[pair[1]]
        for i in group[temp[pair[1]]]:
            temp[i] = temp[pair[0]]
        group.pop(wait)
    elif temp[pair[0]] > temp[pair[1]]:
        group[temp[pair[1]]] += group[temp[pair[0]]]
        wait = temp[pair[0]]
        for i in group[temp[pair[0]]]:
            temp[i] = temp[pair[1]]
        group.pop(wait)
data = list(group.items())
data.sort(key=lambda x:x[0])
print(len(data)-1)
for each in data[1:]:
    ans = each[1]
    ans.sort()
    print(" ".join(map(str,ans)))
一段能过的python代码。
发表于 2021-09-29 22:04:05 回复(0)
我们将每个订单看作一个节点,构建一个并查集。
(1) 刚开始并查集的连通分量有n个(订单数量即为连通分量个数),通过不断地union操作对节点进行合并,每合并一次,并查集的连通分量就减1,合并完成后连通分量的个数就是小区的个数。
(2) 然后对并查集中的parent数组进行遍历,构建一个map,以小区号为key(小区号就是该小区第一个订单的编号),将同一个小区的订单号放入一个list作为对应的value就完成了订单号的归类,之后我们遍历输出每个小区的订单号即可。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.TreeMap;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().trim().split(" ");
        int n = Integer.parseInt(params[0]);
        int m = Integer.parseInt(params[1]);
        UnionFind uf = new UnionFind(n);
        int a, b;
        for(int i = 0; i < m; i++){
            params = br.readLine().trim().split(" ");
            a = Integer.parseInt(params[0]);
            b = Integer.parseInt(params[1]);
            uf.union(a, b);
        }
        // 先输出小区数
        System.out.println(uf.count);
        // 再输出每个小区的订单号
        TreeMap<Integer, ArrayList<Integer>> region = new TreeMap<>();
        ArrayList<Integer> temp;
        for(int i = 1; i <= n; i++){
            if(region.containsKey(uf.parent[i]))
                temp = region.get(uf.parent[i]);
            else
                temp = new ArrayList<>();
            temp.add(i);
            region.put(uf.parent[i], temp);
        }
        for(int id: region.keySet()){
            temp = region.get(id);
            for(int i = 0; i < temp.size(); i++)
                System.out.print(temp.get(i) + " ");
            System.out.println();
        }
    }
}

class UnionFind {
    public int[] parent;
    public int count;
    public UnionFind(int n) {
        count = n;
        parent = new int[n + 1];
        for(int i = 1; i <= n; i++){
            parent[i] = i;
        }
    }
    
    public int find(int x) {
        while(parent[x] != x){
            // 路径压缩
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }
    
    public void union(int x, int y) {
        if(x == y) return;
        int rootX = find(x);
        int rootY = find(y);
        if(rootX == rootY) return;
        // 将节点编号大的合并到节点编号小的节点下面
        if(rootX < rootY){
            for(int i = 0; i < parent.length; ++i){
                if(parent[i] == rootY)
                    parent[i] = rootX;
            }
        }else{
            for(int i = 0; i < parent.length; ++i) {
                if(parent[i] == rootX)
                    parent[i] = rootY;
            }
        }
        count --;
    }
}


编辑于 2021-03-01 22:38:43 回复(0)
import java.util.*;
public class Main {
    public static void main(String[] args) {
        //n为订单数量,m为数量关系
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        UF uf = new UF(n+1);
        for(int i = 0; i < m; i++) {
            uf.union(sc.nextInt(), sc.nextInt());
        }
        //遍历[1, n] 用visited保证只访问一次
        boolean[] visited = new boolean[n+1];
        ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
        for(int i = 1; i <= n; i++) {
            if(!visited[i]) {
                visited[i] = true;
                ArrayList<Integer> list = new ArrayList<>();
                list.add(i);
                for(int j = i+1; j <= n; j++){
                    if(!visited[j] && uf.isConnect(i, j)) {
                        visited[j] = true;
                        list.add(j);
                    }
                }
                ans.add(list);
            }
        }
        System.out.println(ans.size());
        for(int i = 0; i < ans.size(); i++) {
            ArrayList<Integer> list = ans.get(i);
            for(int j = 0; j < list.size(); j++)
                System.out.print(list.get(j) + " ");
            System.out.print("\n");
        }
    }

    static class UF {
        public int[] parents;
        public UF(int n) {
            parents = new int[n];
            for(int i = 0; i < n; i++) parents[i] = i;
        }
        public int find(int i) {
            if(parents[i] != i) {
                parents[i] = find(parents[i]);
            }
            return parents[i];
        }
        public void union(int i, int j) {
            int rootI = find(i);
            int rootJ = find(j);
            parents[rootI] = rootJ;
        }
        public boolean isConnect(int i, int j) {
            return find(i) == find(j);
        }
    }
}
发表于 2021-03-20 11:24:12 回复(0)
不理解并查集的可以看看https://zhuanlan.zhihu.com/p/93647900,讲的很清楚明了
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, m;
    cin >> n >> m;
    vector<int> vec(n + 1), rank(n + 1, 1);
    for (int i = 1; i < n + 1; ++i)
        vec[i] = i;

    function<int(int)> find = [&](int x) -> int
    {
        return x == vec[x] ? x : (vec[x] = find(vec[x]));
    };

    function<void(int, int)> merge = [&](int i, int j) -> void
    {
        int x = find(i), y = find(j);
        if(rank[x] <= rank[y])
            vec[x] = y;
        else
            vec[y] = x;
        if(rank[x] == rank[y] && x != y)
            ++rank[y];
    };

    for (int i = 0; i < m; ++i)
    {
        int a, b;
        cin >> a >> b;
        merge(a, b);
    }

    unordered_map<int, set<int>> um;
    for (int i = 1; i < n + 1; ++i)
        um[find(i)].insert(i);

    auto lambda = [](const set<int> &lhs, const set<int> &rhs)
    {
        return *lhs.begin() < *rhs.begin();
    };
    vector<set<int>> vs;
    for (auto &s : um)
        vs.push_back(std::move(s.second));
    sort(vs.begin(), vs.end(), lambda);

    cout << vs.size() << endl;
    for (const auto &s : vs)
    {
        for (const int val : s)
            cout << val << ' ';
        cout << endl;
    }
}

发表于 2023-03-17 17:44:56 回复(0)
使用HashMap来满足输出条件
import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String[] strs=br.readLine().split(" ");
        int n=Integer.parseInt(strs[0]);
        int m=Integer.parseInt(strs[1]);
        UnionFind uf=new UnionFind(n);
        for(int i=0;i<m;i++){
            strs=br.readLine().trim().split(" ");
            uf.merge(Integer.parseInt(strs[0])-1,Integer.parseInt(strs[1])-1);

        }
        List<ArrayList<Integer>> arraylist=new ArrayList<>();
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<n;i++){
            if(map.get(uf.find(i))==null){
                ArrayList<Integer> list=new ArrayList<>();
                list.add(i);
                arraylist.add(list);
                map.put(uf.find(i),arraylist.size()-1);
            }else{
                ArrayList<Integer> list=arraylist.get(map.get(uf.find(i)));
                list.add(i);
            }
        }
        System.out.println(map.size());
        for(int i=0;i<arraylist.size();i++){
            List<Integer> list=arraylist.get(i);
            for(int j=0;j<list.size();j++){
                System.out.print(list.get(j)+1+" ");
            }
            System.out.println();
        }

    }
}
class UnionFind{
    private int[] parent;
    public UnionFind(int size){
        parent=new int[size];
        for(int i=0;i<size;i++){
            parent[i]=-1;
        }
    }

    public int find(int x){
        int root=x;
        while(parent[root]!=-1){
            root=parent[root];

        }
        while(x!=root){
            int temp=parent[x];
            parent[x]=root;
            x=temp;
        }
        return root;
    }
    public void merge(int x,int y){

        if(find(x)!=find(y)){
            if(find(x)<find(y)){
                parent[find(y)]=x;

            }else{
                parent[find(x)]=y;
            }
        }
    }
}


发表于 2022-08-18 21:54:55 回复(0)
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
int father[10001];
int find(int x){
    if(x==father[x]){
        return x;
    }
    father[x]=father[father[x]];
    return find(father[x]);
}
void unity(int x, int y) {
    int fx = find(x), fy = find(y);
    father[max(fx,fy)]=min(fx,fy);
}
int main(){
    int n,m;
    cin>>n>>m;
    int son,fa;
    for(int i =1;i<=n;i++){
        father[i] =i;
    }
    for(int i=0;i<m;i++){
        cin>>son>>fa;
        unity(son, fa);
    }
    map<int,vector<int>> ans;
    //查询存在几个根节点
    for(int i =1;i<=n;i++){
        vector<int> num;
        if(father[i]==i){
            ans.insert(pair<int,vector<int>>(i, num));
        }
    }
    cout<< ans.size()<<endl;
    for(int i =1;i<=n;i++){
       ans[find(i)].push_back(i);
       //cout<<i<<find(i)<<endl;
    }
    for(auto it = ans.begin();it!=ans.end();it++){
        sort(it->second.begin(),it->second.end());
        for(int i=0;i<it->second.size();i++){
            cout << it->second[i]<<' ';
        }
        cout<<endl;
    }
}
发表于 2022-06-01 22:13:10 回复(0)
"优先输出最小的订单编号较小的小区订单集合"
这句话到底是什么意思啊,为啥我愣是看不懂
发表于 2022-05-10 16:35:14 回复(2)

标准并查集做法

import java.io.*;
import java.util.*;
import java.lang.*;

public class Main{
    static int[] root;
    // 小区数
    static int branches;
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] inputs = br.readLine().trim().split(" ");
        int n = Integer.parseInt(inputs[0]);
        // 已知关系数量
        int m = Integer.parseInt(inputs[1]);
        root = new int[n+1];
        branches = n;
        for(int i=1;i<=n;++i){
            root[i] = i;
        }
        for(int i=0;i<m;++i){
            inputs = br.readLine().trim().split(" ");
            int x = Integer.parseInt(inputs[0]);
            int y = Integer.parseInt(inputs[1]);
            union(x,y);
        }
        for(int i=1;i<=n;++i){
            root[i] = find(i);
        }
        //System.out.println(Arrays.toString(root));
        //System.out.println(branches);
        // <小区代表元素,小区编号>
        Map<Integer,Integer> map = new HashMap<>();
        // 各个小区的订单,按照编号排序
        List<List<Integer>> areas = new ArrayList<>();
        int cnt = 0;
        for(int i=1;i<=n;++i){
            // 如果出现一个新的root,表示出现了一个新的小区,给小区编号,且这个root就是该小区最小的订单号
            // 并增加一个list到小区列表中
            if(!map.containsKey(root[i])){
                map.put(root[i],cnt);
                cnt++;
                areas.add(new ArrayList<>());
            }
            int num = map.get(root[i]);
            areas.get(num).add(i);
        }
        System.out.println(branches);
        // 因为是按顺序处理的订单,所以结果已经有序,直接输出
        for(List<Integer> list:areas){
            for(int t:list){
                System.out.print(t+" ");
            }
            System.out.println();
        }
    }

    public static int find(int x){
        return x == root[x]?x:(root[x] = find(root[x]));
    }

    public static void union(int x,int y){
        int rootX = find(x);
        int rootY = find(y);
        if(rootX!=rootY){
            root[rootX] = rootY;
            branches--;
        }
    }
}
发表于 2022-03-10 15:48:16 回复(0)
通过堆+hash对每个联通量进行处理,由于节点数为n,边数为m,算法复杂度为(nlogn+m),耗时20ms。
#include<iostream>
#include<queue>
#include<map>
#include<vector>
using namespace std;
int main(void) {
	int m = 0, n = 0;
	cin >> m;
	cin >> n;
	map<int, int> mp;
	vector<priority_queue<int, vector<int>, greater<int>>> vec(m + 1);
	for (int i = 1; i <= m; i++) {
		vec[i].push(i);
		mp[i] = i;
	}
	for (int i = 0; i < n; i++) {
		int a = 0;
		int b = 0;
		cin >> a;
		cin >> b;
		a = vec[mp[a]].top();
		b = vec[mp[b]].top();
		if (a > b) {
			int tmp = a;
			a = b;
			b = tmp;
		}
		else if (a == b)continue;
		mp[b] = a;
		auto tmp = &vec[a];
		while (!vec[b].empty()) {
			vec[a].push(vec[b].top());
			mp[vec[b].top()] = a;
			vec[b].pop();
		}
	}
	int count = 0;
	vector<int> has_district(n, 0);
	for (auto& [key, value] : mp) {
		if (has_district[value] == 0)count++;
		has_district[value] = 1;
	}
	cout << count << endl;
	for (int i = 0; i < n; i++) {
		if (has_district[i]) {
			cout << vec[i].top();
			vec[i].pop();
			while (!vec[i].empty()) {
				cout << " " << vec[i].top();
				vec[i].pop();
			}
			cout << endl;
		}
	}
}


发表于 2021-08-06 02:01:44 回复(0)
#include <bits/stdc++.h>
 
using namespace std;
 
int parents[10000];
 
void init(int n) {
    for (int i = 1; i <= n; ++i) {
        parents[i] = i;
    }
}
 
int find(int x) {
    return x == parents[x] ? x : (parents[x] = find(parents[x]));
}
 
void comb(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
        return;
    } else if (x > y) {
        comb(y, x);
    } else {
        parents[y] = x;
    }
}
 
int main() {
    int m, n;
    cin >> m >> n;
    init(n);
    while (m--) {
        int a, b;
        cin >> a >> b;
        comb(a, b);
    }
    int cnt = 0;
    map<int, vector<int>> mp;
    for (int i = 1; i <= n; ++i) {
        parents[i] = find(i);
        if (mp[parents[i]].size() == 0) {
            ++cnt;
        }
        mp[parents[i]].emplace_back(i);
    }
    cout << cnt << endl;
    for (auto it = mp.begin(); it != mp.end(); ++it) {
        vector<int> tmp = it->second;
        cout << tmp[0];
        for (int i = 1; i < tmp.size(); ++i) {
            cout << ' ' << tmp[i];
        }
        cout << endl;
    }
     
    return 0;
}

发表于 2021-03-02 16:37:50 回复(0)