Алгоритм проверки того, могут ли учащиеся распределяться по классам в соответствии с их предпочтениями

#algorithm

Вопрос:

В хакатоне по кодированию у меня возникла следующая проблема :

Существует K классов, каждый из которых обладает определенной емкостью. Есть N студентов, и у каждого есть одно или два предпочтения в классе. Нам нужно напечатать «ДА», если все учащиеся могут быть распределены в класс, или «НЕТ».

Например :

 
N = 4
K = 3
capacity = {2,1,1}
preference = {"0","0,2","1","2"}

 

Есть 4 студента и 3 класса, и в соответствии с их предпочтениями могут быть выделены следующие классы:

Студенты Классы
0 0
1 0
2 1
3 2

Таким образом, ответом на вышеприведенный сценарий будет «ДА»

Каков будет алгоритм подхода к решению вышеуказанной проблемы?

Обновить:

Я использовал объяснение Кристиана ниже, чтобы придумать следующее решение:

 import java.util.*;
public class StudentAllocation{

    public static void main(String args[]){
        int N = 4;
        int K = 3;
        int capacity[] = {2,1,1};
        String preference[] = {"0","0,2","1","2"};
        System.out.println(canAllocate(N,K,capacity,preference));
    }
    public static String canAllocate(int N,int K,int c[],String p[]){
        //Creating nodes for each student and capacity*class
        //Also making one node for source and on node for sink
        HashMap<String,Integer> nm = new HashMap<String,Integer>();
        int n = 1;
        for(int i = 0;i < N;i  ){
            nm.put("s" i,n  );
        }
        for(int i = 0;i < c.length;i  ){
            for(int j = 0;j < c[i];j  ){
                nm.put("c" i j,n  );
            }
        }
        n = n 1;
        int[][] g = new int[n][n];
        //connecting source to all student nodes
        for(int i = 1;i <= N;i  ){
            g[0][i] = 1;
        }
        //connecting all capacity*class nodes to sink
        for(int i = N 1;i < n-1;i  ){
            g[i][n-1] = 1;
        }
        //Connecting student node to all the capcity node of class of his preference
        for(int i = 0;i < p.length;i  ){
            String ps = p[i];
            String pst[] = ps.split(",");
            for(int j = 0;j < pst.length;j  ){
                for(int k = 0;k < c[Integer.parseInt(pst[j])];k  ){
                    g[nm.get("s" i)][nm.get("c" pst[j] k)] = 1;
                    g[nm.get("s" i)][nm.get("c" pst[j] k)] = 1;
                }
            }
        
        }
        //Using Ford Fulkerson to callculate max flow
        // If max flow is equal to no of students then each student can be allocated to any class of his preference
        //Making residual graph
        int rg[][] = new int[n][n];
        
        for(int i = 0;i < n;i  ){
            for(int j = 0;j < n;j  ){
                rg[i][j] = g[i][j];
            }
        }
        
        int parent[] = new int[n];
        int max_flow = 0;
        int count = 0;
        while(bfs(rg,0,n-1,parent)){
            count  ;
            
            int path_flow = Integer.MAX_VALUE;
            for(int i = n-1;i != 0;i = parent[i]){
                path_flow = Math.min(path_flow,rg[parent[i]][i]);
            }
            
            max_flow = max_flow   path_flow;
            for(int i = n-1;i != 0;i = parent[i]){
                rg[parent[i]][i] -= path_flow;
                rg[i][parent[i]]  = path_flow;
            }
            
        }
        if(max_flow == N){
            return "YES";
        }
        return "NO";    
        
    }
    
    public static boolean bfs(int rg[][],int u, int v, int[] p){
        ArrayDeque<Integer> q = new ArrayDeque<Integer>();
        q.offer(u);
        int marked[] = new int[rg.length];
        while(!q.isEmpty()){
            u = q.poll();
            marked[u] = 1;

            for(int i = 0;i < rg[u].length;i  ){
                if(marked[i] != 1 amp;amp; rg[u][i] > 0){
                    p[i] = u;
                    q.add(i);
                    if(i == v){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
    
}

 

Комментарии:

1. это тебя раздражает? cs.stackexchange.com/questions/49153/…

Ответ №1:

Вы можете создать двудольный граф с узлами учащихся на одной стороне, а затем на другой стороне создать узлы емкости класса*. Каждый узел представляет одну точку в классе.

Ребро от учащегося к узлу класса означает, что этот учащийся готов занять это место. Обратите внимание, что студент готов занять любое место в классе, которому он отдает предпочтение.

Тогда проблема заключается в том, чтобы найти идеальное соответствие в этом графике. Если такое соответствие существует, это «ДА», если нет, это «НЕТ».

Ответ №2:

Вот рекурсивный алгоритм. Мы рассматриваем последнего студента, пробуем его первый выбор и проверяем, может ли быть решена проблема для оставшихся n-1 студентов. Если нет, попробуйте второй вариант (если есть), и снова проверьте проблему для оставшихся учеников.

Вот реализация на PHP (вы можете протестировать ее здесь):

 <?php
function isSolvable($choices1, $choices2, $capacities, $n)
{
    if($n==0)
        return true; // No students left to allocate

    // First choice of student $n
    $c1 = $choices1[$n-1];
    if($capacities[$c1]>0)
    {
        $capacities[$c1]--;
        if(isSolvable($choices1, $choices2, $capacities, $n-1))
            return true;
        $capacities[$c1]  ;
    }

    // Second choice of student $n
    $c2 = $choices2[$n-1];
    if($c2>=0 amp;amp; $capacities[$c2]>0)
    {
        $capacities[$c2]--;
        if(isSolvable($choices1, $choices2, $capacities, $n-1))
            return true;
    }

    return false;
}

$choices1 = [0, 0, 1, 2];
$choices2 = [-1, 2, -1, -1];
$capacities = [2, 1, 1];
echo isSolvable($choices1, $choices2, $capacities, count($choices1)) ? 'YES' : 'NO';
?>