In this HackerRank Training the army problem solution Your goal is to design a series of transformations that results in a maximum number of skill sets with a non-zero number of people knowing it.

HackerRank Training the army problem solution


Problem solution in Python.

import collections

class Node:
    def __init__(self, id_):
        self.id = id_
        self.residual_flows = {}

class MaxFlow_LinkedList:
    INF = 100000
    
    def __init__(self, N_):
        self.N = N_
        
        self.node_table = []
        for i in range(0, self.N):
            self.node_table.append(Node(i))
            
        self.source = 0
        self.sink = N_ - 1
        
        self.max_flow = 0
        
        self.parent_links = [-1] * self.N
        
        self.main_flows = []
        
    def getMainFlows(self):
        net_flows = []
        for [u, v, c] in self.main_flows:
            net_flows.append([u, v, c, self.node_table[v].residual_flows[u]])
        return net_flows
        
    def addCapacity(self, u, v, c):
        self.node_table[u].residual_flows[v] = c
        self.node_table[v].residual_flows[u] = 0
        
        self.main_flows.append([u, v, c])
        
    def addCapacityBoth(self, u, v, c_uv, c_vu):
        self.node_table[u].residual_flows[v] = c_uv
        self.node_table[v].residual_flows[u] = c_vu
        
        self.main_flows.append([u, v, c_uv])
        self.main_flows.append([v, u, c_vu])            
            
    def bfs(self):
        visited = [False] * self.N
        
        pending = collections.deque();
        
        visited[self.source] = True
        pending.append(self.source)
        self.parent_links[self.source] = -1
        
        while len(pending) > 0:
            curr_node = pending.popleft()
            
            if curr_node == self.sink:
                return True
            
            for adj_node, res_flow in self.node_table[curr_node].residual_flows.items():
                if res_flow > 0 and not visited[adj_node]:
                    self.parent_links[adj_node] = curr_node
                    pending.append(adj_node)
                    visited[adj_node] = True
                    
        return False
    
    def findMaxFlow(self):
        max_total_flow = 0
        
        while self.bfs():
            
            # find maximum possible flow in the BFS path
            max_path_flow = MaxFlow_LinkedList.INF
            v = self.sink
            while v != self.source:
                u = self.parent_links[v]
                max_path_flow = min(max_path_flow, self.node_table[u].residual_flows[v])
                v = u
            
            # modify the residual flows:
            # - remove the flow from residual flows from source to sink
            # - add the flow to residual flows from sink to source
            
            v = self.sink
            while v != self.source:
                u = self.parent_links[v]
                self.node_table[u].residual_flows[v] -= max_path_flow
                self.node_table[v].residual_flows[u] += max_path_flow
                v = u
            
            max_total_flow += max_path_flow
            
        return max_total_flow
    

[n, k] = list(map(int, input().split()))
C = list(map(int, input().split()))

A = []
B = []

for i in range(0, k):
    a = list(map(int, input().split()))
    b = list(map(int, input().split()))
    
    A.append(a[1:])
    B.append(b[1:])
    
def getAIdx(w, i):
    return sum(len(a) for a in A[:w]) + i + 1 + n*2

def getBIdx(w, i):
    return sum(len(a) for a in A) + sum(len(b) for b in B[:w]) + i + 1 + 2*n

# total nodes = 1sink + 1source + 2*N + sum_of_sizes_A + sum_of_sizes_B
total_nodes = 2 + 2 * n + sum(len(a) for a in A) + sum(len(b) for b in B)

flow_network = MaxFlow_LinkedList(total_nodes)

for [i, c] in enumerate(C):
    flow_network.addCapacity(0, i+1, c)
    flow_network.addCapacityBoth(i+1, n+1+i, 1, 1000000)
    flow_network.addCapacity(n+1+i, total_nodes-1, 1)

for w in range(0, len(A)):
    for i in range(0, len(A[w])):
        flow_network.addCapacity(A[w][i], getAIdx(w, i), 1)
        
for w in range(0, len(B)):
    for i in range(0, len(B[w])):
        flow_network.addCapacity(getBIdx(w, i), n+B[w][i], 1)
        
for w in range(0, len(A)):
    for i in range(0, len(A[w])):
        for j in range(0, len(B[w])):
            flow_network.addCapacity(getAIdx(w, i), getBIdx(w, j), 1)
            
print (flow_network.findMaxFlow())

{"mode":"full","isActive":false}


Problem solution in Java.

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

public class Solution {
    private static Reader in;
    private static PrintWriter out;

    public static void main(String[] args) throws IOException {
        in = new Reader();
        out = new PrintWriter(System.out, true);

        int M = in.nextInt(), T = in.nextInt();
        N = 2 + M + T * 2;
        E = 2 * N + N * T * 2 + T;
        flow = new int[2 * E];
        capa = new int[2 * E];
        now = new int[N];
        eadj =new int[2 * E];
        eprev = new int[2 * E];
        elast = new int[N];
        level = new int[N];
        Arrays.fill (elast, -1);
        eidx = 0;
        
        for (int i = 0; i < M; i++) {
            int a = in.nextInt();
            if (a != 0) { 
                add_edge(N - 1, i, a);
            }
            add_edge(i, N - 2, 1);
        }

        for (int i = 0; i < T; i++) {
            int num = in.nextInt();
            for (int j = 0; j < num; j++) {
                add_edge(in.nextInt() - 1, M + i, 1);
            }
            
            num = in.nextInt();
            for (int j = 0; j < num; j++) {
                add_edge(M + i, in.nextInt() - 1, 1);
            }
            
        }

        out.println(dinic(N - 1, N - 2));
        out.close();
        System.exit(0);
    }

    private static int []   flow, capa, now;
    public static int[] eadj, eprev, elast;
    public static int eidx;
    public static int N, E;
    public static int INF = 1 << 29;

    private static void add_edge (int a, int b, int c) {
        eadj[eidx] = b; 
        flow[eidx] = 0; 
        capa[eidx] = c; 
        eprev[eidx] = elast[a]; 
        elast[a] = eidx++;
        eadj[eidx] = a; 
        flow[eidx] = c; 
        capa[eidx] = c; 
        eprev[eidx] = elast[b]; 
        elast[b] = eidx++;
    }

    private static int dinic (int source, int sink) {
        int res, flow = 0;
        while (bfs (source, sink)) { // see if there is an augmenting path
            System.arraycopy (elast, 0, now, 0, N);
            while ((res = dfs (source, INF, sink)) > 0) { // push all possible flow through
                flow += res;
            } 
        }
        return flow;
    }

    private static int []   level;

    private static boolean bfs (int source, int sink) {
        Arrays.fill (level, -1);
        int front = 0, back = 0;
        int [] queue = new int [N];
        
        level[source] = 0;
        queue[back++] = source;
        
        while (front < back && level[sink] == -1) {
            int node = queue[front++];
            for (int e = elast[node]; e != -1; e = eprev[e]) {
                int to = eadj[e];
                if (level[to] == -1 && flow[e] < capa[e]) {
                    level[to] = level[node] + 1;
                    queue[back++] = to;
                }
            }
        }
        return level[sink] != -1;
    }

    private static int dfs (int cur, int curflow, int goal) {
        if (cur == goal) {
            return curflow;
        }
            
        
        for (int e = now[cur]; e != -1; now[cur] = e = eprev[e]) {
            if (level[eadj[e]] > level[cur] && flow[e] < capa[e]) {
                int res = dfs (eadj[e], Math.min (curflow, capa[e] - flow[e]), goal);
                if (res > 0) {
                    flow[e] += res;
                    flow[e ^ 1] -= res;
                    return res;
                }
            }
        }
        return 0;
    }

    static class Reader {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader() {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException {
            byte[] buf = new byte[1024];
            int cnt = 0, c;
            while ((c = read()) != -1) {
            if (c == '\n')
                break;
            buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
            c = read();
            boolean neg = (c == '-');
            if (neg)
            c = read();
            do {
            ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg)
            return -ret;
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
            c = read();
            boolean neg = (c == '-');
            if (neg)
            c = read();
            do {
            ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg)
            return -ret;
            return ret;
        }

        public double nextDouble() throws IOException {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
            c = read();
            boolean neg = (c == '-');
            if (neg)
            c = read();
            do {
            ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (c == '.')
            while ((c = read()) >= '0' && c <= '9')
                ret += (c - '0') / (div *= 10);
            if (neg)
            return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
            buffer[0] = -1;
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead)
            fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException {
            if (din == null)
            return;
            din.close();
        }
    }
}

{"mode":"full","isActive":false}


Problem solution in C++.

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAXN = 10000;
const int MAXM = 100000;
const ll inf = 1LL << 50;

int cnt, box[MAXN], pre[MAXN], gap[MAXN], h[MAXN], cur[MAXN];
int N, NS, NT;
ll flow[MAXN];

struct edge {
    int to, ne;
    ll w;
} e[MAXM * 2];

void adds(int u, int v, ll w) {
    e[cnt].to = v;
    e[cnt].w = w;
    e[cnt].ne = box[u];
    box[u] = cnt++;
}

void add(int u, int v, ll w) {
    adds(u, v, w);
    adds(v, u, 0LL);
}

ll mins(ll x, ll y) {
    return x < y ? x : y;
}

int qu[MAXN];

void bfs() {
    memset(h,-1,sizeof(h));
    memset(gap,0,sizeof(gap));
    h[NT]=0;
    gap[0]=1;
    int st=0,ed=1;
    qu[ed]=NT;
    while(st!=ed) {
        int u=qu[++st];
        for(int p=box[u]; p!=-1; p=e[p].ne)
            if (h[e[p].to]==-1) {
                h[e[p].to]=h[u]+1;
                qu[++ed]=e[p].to;
                ++gap[ h[e[p].to]=h[u]+1 ];
            }
    }
}

ll sap() {
    int u,v,p;

    ll flowans=0;
    //memset(gap,0,sizeof(gap));gap[0]=N;
    // memset(h,0,sizeof(h));
    bfs();
    for(int i=0; i<N; i++) cur[i]=box[i];
    flow[NS]=inf;
    u=NS;
    while(h[NS]<N) {
        for(p=cur[u]; p!=-1; p=e[p].ne)
            if (e[p].w&&h[e[p].to]+1==h[u]) {
                cur[u]=p;
                v=e[p].to;
                flow[v]=mins(flow[u],e[p].w);
                pre[v]=p;
                u=v;
                if (u==NT) {
                    flowans+=flow[NT];
                    while(u!=NS) {
                        e[pre[u]].w-=flow[NT];
                        e[pre[u]^1].w+=flow[NT];
                        u=e[pre[u]^1].to;
                    }
                }
                break;
            }
        if (p==-1) {
            cur[u]=box[u];
            if (--gap[h[u]]==0) break;
            h[u]=N;
            for(p=box[u]; p!=-1; p=e[p].ne)
                if (e[p].w&&h[e[p].to]+1<h[u])
                    h[u]=h[e[p].to]+1;
            gap[h[u]]++;
            if (u!=NS) u=e[pre[u]^1].to;
        }
    }
    return flowans;
}

int main() {
    memset(box, -1, sizeof(box));
    cnt = 0;
    int n, m;
    scanf("%d%d", &n, &m);
    N = n + m * 2 + 2;
    NS = N - 1;
    NT = N - 2;
    for (int i = 0; i < n; i ++) {
        int val;
        scanf("%d", &val);
        add(NS, i, val);
        add(i, NT, 1);
    }
    int cntx = n;
    for (int i = 0; i < m; i ++) {
        for (int j = 0; j < 2; j ++) {
            int num;
            scanf("%d", &num);
            for (int k = 0; k < num; k ++) {
                int p;
                scanf("%d", &p);
                if (j == 0) {
                    add(p - 1, cntx, 1);
                } else {
                    add(cntx, p - 1, 1);
                }
            }
            cntx ++;
        }
        add(cntx - 2, cntx - 1, inf);
    }
    printf("%lld\n", sap());
    return 0;
}

{"mode":"full","isActive":false}


Problem solution in C.

#include <stdio.h>
#include <stdlib.h>
typedef struct _node{
  int x;
  struct _node* next;
} node;
typedef struct _queue{
  node *head;
  node *tail;
} queue;
typedef struct _list_node{
  int x;
  int c;
  int *p;
  struct _list_node *next;
} list_node;
void add_edge(int x,int y,int c);
void list_insert(list_node **head,list_node *x);
void ini_q();
void free_q();
void en_q(node *x);
int de_q();
queue q;
list_node **table;

int main(){
  int N,T,ALen=0,BLen=0,AC,BC,t,i,j,k,ans=0;
  int **A,**B,*C,*AA,*BB,*pp;
  node *tt;
  list_node *temp;
  scanf("%d%d",&N,&T);
  A=(int**)malloc(T*sizeof(int*));
  B=(int**)malloc(T*sizeof(int*));
  C=(int*)malloc(N*sizeof(int));
  for(i=0;i<N;i++)
    scanf("%d",C+i);
  for(i=0;i<T;i++){
    scanf("%d",&t);
    ALen+=t;
    A[i]=(int*)malloc((t+1)*sizeof(int));
    A[i][0]=t;
    for(j=1;j<=t;j++){
      scanf("%d",&A[i][j]);
      A[i][j]--;
    }
    scanf("%d",&t);
    BLen+=t;
    B[i]=(int*)malloc((t+1)*sizeof(int));
    B[i][0]=t;
    for(j=1;j<=t;j++){
      scanf("%d",&B[i][j]);
      B[i][j]--;
    }
  }
  table=(list_node**)malloc((N+ALen+BLen+2)*sizeof(list_node*));
  AA=(int*)malloc(ALen*sizeof(int));
  BB=(int*)malloc(BLen*sizeof(int));
  pp=(int*)malloc((N+ALen+BLen+2)*sizeof(int));
  for(i=0;i<N+ALen+BLen+2;i++)
    table[i]=NULL;
  for(i=0;i<N;i++){
    if(C[i])
      add_edge(N+ALen+BLen,i,C[i]);
    add_edge(i,N+ALen+BLen+1,1);
  }
  AC=BC=0;
  for(i=0;i<T;i++){
    for(j=0;j<A[i][0];j++)
      for(k=0;k<B[i][0];k++)
        if(A[i][j+1]!=B[i][k+1])
          add_edge(N+AC+j,N+ALen+BC+k,1);
    for(j=0;j<A[i][0];j++)
      AA[AC++]=A[i][j+1];
    for(j=0;j<B[i][0];j++)
      BB[BC++]=B[i][j+1];
  }
  for(i=0;i<N;i++){
    for(j=0;j<ALen;j++)
      if(AA[j]==i)
        add_edge(i,N+j,1);
    for(j=0;j<BLen;j++)
      if(BB[j]==i)
        add_edge(N+ALen+j,i,1);
  }
  do{
    for(i=0;i<N+ALen+BLen+2;i++)
      pp[i]=-1;
    pp[N+ALen+BLen]=N+ALen+BLen;
    ini_q();
    tt=(node*)malloc(sizeof(node));
    tt->x=N+ALen+BLen;
    en_q(tt);
    while(q.head){
      t=de_q();
      for(temp=table[t];temp;temp=temp->next)
        if(temp->c && pp[temp->x]==-1){
          pp[temp->x]=t;
          if(temp->x==N+ALen+BLen+1)
            goto out;
          tt=(node*)malloc(sizeof(node));
          tt->x=temp->x;
          en_q(tt);
        }
    }
    out:
    free_q();
    t=N+ALen+BLen+1;
    pp[N+ALen+BLen]=-1;
    while(pp[t]!=-1){
      for(temp=table[pp[t]];temp;temp=temp->next)
        if(temp->x==t){
          temp->c--;
          (*(temp->p))++;
          break;
        }
      t=pp[t];
    }
    if(pp[N+ALen+BLen+1]!=-1)
      ans++;
  }while(pp[N+ALen+BLen+1]!=-1);
  printf("%d",ans);
  return 0;
}
void add_edge(int x,int y,int c){
  list_node *t1,*t2;
  t1=(list_node*)malloc(sizeof(list_node));
  t2=(list_node*)malloc(sizeof(list_node));
  t1->x=y;
  t1->c=c;
  t2->x=x;
  t2->c=0;
  t1->p=&(t2->c);
  t2->p=&(t1->c);
  list_insert(&table[x],t1);
  list_insert(&table[y],t2);
  return;
}
void list_insert(list_node **head,list_node *x){
  x->next=*head;
  *head=x;
  return;
}
void ini_q(){
  q.head=q.tail=NULL;
  return;
}
void free_q(){
  node *p=q.head,*t;
  while(p){
    t=p;
    p=p->next;
    free(t);
  }
  return;
}
void en_q(node *x){
  if(!q.tail){
    q.head=q.tail=x;
    x->next=NULL;
  }
  else{
    q.tail->next=x;
    q.tail=x;
    q.tail->next=NULL;
  }
  return;
}
int de_q(){
  int x=q.head->x;
  node *p=q.head;
  q.head=q.head->next;
  if(q.head==NULL)
    q.tail=NULL;
  free(p);
  return x;
}

{"mode":"full","isActive":false}