Cod sursa(job #1708402)

Utilizator stefanrStefan Ruseti stefanr Data 26 mai 2016 23:55:25
Problema Robo Scor Ascuns
Compilator java Status done
Runda Marime 16.99 kb
/**
 * Created by matei on 22/05/16.
 */

import javax.sound.midi.Soundbank;
import javax.xml.bind.SchemaOutputResolver;
import java.io.*;
import java.util.*;

class Triple <T1,T2,T3> {
    T1 v1;
    T2 v2;
    T3 v3;
    public Triple(T1 v1, T2 v2, T3 v3){
        this.v1 = v1; this.v2 = v2; this.v3 = v3;
    }
    public T1 fst(){ return v1;}
    public T2 snd(){ return v2;}
    public T3 thrd(){ return v3;}
}

class NFA {
    /*
     Convention for reading an automata:
     n m
     f1 f2 ... fk
     s c sp
     ...
     s c sp

     n - number of states
     m - number of symbols
     f1 f2 ... fk - the final states
     s c p - transition (state symbol state)

  */
    private int state_no, symbol_no;
    List<Integer> [][] m;
    List<Integer> [][] invm;
    List<Integer> final_states;
    List<Integer> initial_states;


    boolean isFinal (Integer s){
        return final_states.contains(s);
    }
    public NFA (int state_no, int symbol_no){
        init(state_no,symbol_no);
    }
    private void init (int state_no, int symbol_no){
        this.state_no = state_no;
        this.symbol_no = symbol_no;
        m = new LinkedList[state_no][symbol_no];
        invm = new LinkedList[state_no][symbol_no];
        final_states = new LinkedList<Integer>();
        initial_states = new LinkedList<Integer>();
        initial_states.add(0);
    }
    public NFA(BufferedReader reader){
        try
        {
            //BufferedReader reader = new BufferedReader(new FileReader(filename));
            String line;
            String[] toks;
            line = reader.readLine(); // states and symbols

            toks = line.split("\\s+");
            init(Integer.parseInt(toks[0]), Integer.parseInt(toks[1]));

            line = reader.readLine();
            toks = line.split("\\s+");
            for (String i:toks)
                final_states.add(Integer.parseInt(i));

            while (!(line = reader.readLine()).trim().equals(""))
            {
                toks = line.split("\\s+");
                char c = toks[1].charAt(0);
                Integer s = Integer.parseInt(toks[0]);
                Integer sp = Integer.parseInt(toks[2]);
                if (m[s][c-'a'] == null)
                    m[s][c - 'a'] = new LinkedList<Integer>();

                if (invm[sp][c-'a'] == null)
                    invm[sp][c - 'a'] = new LinkedList<Integer>();

                m[s][c - 'a'].add(sp);
                invm[sp][c - 'a'].add(s);

            }

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    public NFA(String filename){
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(filename));
            String line;
            String[] toks;
            line = reader.readLine(); // states and symbols

            toks = line.split("\\s+");
            init(Integer.parseInt(toks[0]), Integer.parseInt(toks[1]));

            line = reader.readLine();
            toks = line.split("\\s+");
            for (String i:toks)
                final_states.add(Integer.parseInt(i));

            while ((line = reader.readLine()) != null)
            {
                toks = line.split("\\s+");
                char c = toks[1].charAt(0);
                Integer s = Integer.parseInt(toks[0]);
                Integer sp = Integer.parseInt(toks[2]);
                if (m[s][c-'a'] == null)
                    m[s][c - 'a'] = new LinkedList<Integer>();

                if (invm[sp][c-'a'] == null)
                    invm[sp][c - 'a'] = new LinkedList<Integer>();

                m[s][c - 'a'].add(sp);
                invm[sp][c - 'a'].add(s);

            }
            reader.close();
        }
        catch (Exception e)
        {
            System.err.format("Exception occurred trying to read '%s'.", filename);
            e.printStackTrace();
        }
    }

    public int size (){ return state_no;}
    public int symbols () {return symbol_no;}
    public int final_states(){return final_states.size();}
    public List<Integer> get_nonfinal_states(){
        List<Integer> r = new LinkedList<Integer>();
        for (int i = 0; i<state_no; i++)
            if (!isFinal(i))
                r.add(i);
        return r;
    }
    public List<Integer> get_final_states(){
        return final_states;
    }

    // returns the list of states from which a state in S is reachable via symbol
    public Set<Integer> inv (int symbol, Set<Integer> S){
        Set<Integer> r = new HashSet<Integer>();
        for (Integer s:S)
            if (invm[s][symbol] != null)
                r.addAll(invm[s][symbol]);

        return r;
    }
    @Override
    public String toString(){
        String s = "# ";
        for (int i=0; i<symbol_no; i++)
            s += Character.toString((char)(i + 'a'))+" ";
        s+="\n";
        for (int i=0; i<state_no; i++){
            s += Integer.toString(i)+" ";
            for (int j = 0; j<symbol_no; j++) {
                if (m[i][j] != null)
                    s += m[i][j].toString();
                else
                    s += "[]";
            }
            s += "\n";
        }
        return s;
    }


    public Set<Integer> move(int c, Set<Integer> q) {
        Set<Integer> r = new HashSet<Integer>();
        for (Integer s:q)
            if (m[s][c] != null)
                r.addAll(m[s][c]);
        return r;
    }

    public void add_transition(int s, int c, int sp){

        if (m[s][c] == null)
            m[s][c] = new LinkedList<Integer>();
        if (invm[sp][c] == null)
            invm[sp][c] = new LinkedList<Integer>();
        m[s][c].add(sp);
        invm[sp][c].add(s);
    }

    public void add_final_state(int s){
        final_states.add(s);
    }
}

public class Main {


    public static <T> Set<T> setmin (Set<T> s1, Set<T> s2){
        if (s1.size() > s2.size())
            return s2;
        return s1;
    }
    public static <T> boolean refine (Set<T> Y1, Set<T> Y2, Set<T> Y, Set<T> X){
        for (T t:Y){
            if (X.contains(t))
                Y1.add(t);
            else Y2.add(t);
        }
        if (Y1.size() == 0 || Y2.size() == 0)
            return false;
        return true;
    }
    public static NFA det (NFA A){

        List<Triple<List<Integer>,Integer,List<Integer>>> delta = new LinkedList<Triple<List<Integer>,Integer,List<Integer>>>();
        List<Set<Integer>> Q = new LinkedList<Set<Integer>>();
        Set<Integer> q0 = new HashSet<Integer>();
        for (Integer si:A.initial_states)
            q0.add(si);
        Q.add(q0);

        List<Integer> F = new LinkedList<Integer>();
        List<Set<Integer>> mark = new LinkedList<Set<Integer>>();
        Set<Integer> q, qp;
        ListIterator<Set<Integer>> it;
        boolean flag = true;
        while(flag) {
                flag = false;          // new traversal started
            for (it = Q.listIterator(); it.hasNext(); ) {
                //System.out.println("Q is " + Q);
                q = it.next();
                //System.out.println("Current q is " + q);
                if (!mark.contains(q)) {
                    mark.add(q);

                    for (Integer c = 0; c < A.symbols(); c++) {
                        qp = A.move(c, q);
                        if (qp.isEmpty())
                            continue;
                        //System.out.println("Qp is:" + qp + " for " + (char) (c + 'a'));
                        if (!Q.contains(qp)) {
                            //System.out.println("Adding " + qp);
                            it.add(qp);
                            flag = true; // list modification. A new traversal is allowed0.

                        }
                        //System.out.println("Trans " + q + " " + (char) (c + 'a') + " " + qp);
                        delta.add(new Triple(q, c, qp));

                    }
                }
            }
        } // end of while

        NFA det = new NFA(Q.size(),A.symbols());
        //System.out.println("Q is "+Q);

        for (Triple<List<Integer>,Integer,List<Integer>> t:delta) { // the initial state is guaranteed to be the first
            //System.out.println("Transition "+t.fst()+" "+(char)(t.snd()+'a')+" "+t.thrd());
            det.add_transition(Q.indexOf(t.fst()), t.snd(), Q.indexOf(t.thrd()));
        }

        for(Set<Integer> qq:mark)
            for (Integer s:qq)
               if(A.isFinal(s))
                   det.add_final_state(mark.indexOf(qq));

        return det;

    }

    public static NFA rev (NFA A){
        NFA rev = new NFA(A.size(),A.symbols());
        rev.final_states = A.initial_states;
        rev.initial_states = A.final_states;

        rev.m = A.invm;
        rev.invm = A.m;

        return rev;
    }

    public static boolean isTotal (NFA A){
        for (int i=0; i<A.size(); i++)
            for (int j=0; j<A.symbols(); j++)
                if (A.m[i][j]== null || A.m[i][j].size()==0)
                    return false;
        return true;
    }

    public static int hopcroft (NFA a){

        List<Set<Integer>> P = new LinkedList<Set<Integer>>();
        Set<Integer> sf = new HashSet(a.get_final_states());
        Set<Integer> snf = new HashSet(a.get_nonfinal_states());
        P.add(sf);
        P.add(snf);

        List<Set<Integer>> W = new LinkedList<Set<Integer>>();
        W.add(setmin(sf, snf));

        while (!W.isEmpty()){
            Set<Integer> A = W.get(0);
            W.remove(0);
            for (int c = 0; c<a.symbols();c++) {
                for (ListIterator<Set<Integer>> it = P.listIterator(); it.hasNext();) {
                    Set<Integer> Y = it.next();
                    Set<Integer> Y1 = new HashSet<Integer>(), Y2 = new HashSet<Integer>();
                    //System.out.println("[W="+W+"]Processing "+Y);
                    if (refine(Y1, Y2, Y, a.inv(c, A))) { // we have a partition
                        //System.out.println("Refining " + Y + " by " + Y1 + " and " + Y2);
                        it.remove();
                        it.add(Y1);
                        it.add(Y2);
                        if (W.contains(Y)) {
                            W.remove(Y);
                            W.add(Y1);
                            W.add(Y2);
                        } else
                            W.add(setmin(Y1, Y2));
                    }
                }
            }
        }

        //System.out.println(P);



        return P.size();
    }

    //concatenation of two automata over the same alphabet
    // it is assumed that a has a single final state having only sink-state transitions,
    public static NFA concatenate (NFA a, NFA b){
        NFA res = new NFA(a.size()+b.size()-1,a.symbols());

        for (int i=0; i<a.size();i++){
            for (int c=0; c<a.symbols(); c++){
                if (a.isFinal(i)) {
                    if (b.m[0][c] != null && !b.m[0][c].isEmpty())
                        for (Integer next : b.m[0][c]) {
                            res.add_transition(i, c, a.size() + next - 1);
                        }
                }
                else
                    if (a.m[i][c] != null){
                        for (Integer next:a.m[i][c])
                            res.add_transition(i,c,next);
                    }
            }
        }

        for (int i=1; i<b.size();i++){
            for (int c=0; c<b.symbols(); c++){
                if (b.m[i][c] != null)
                    for (Integer next:b.m[i][c])
                        res.add_transition(a.size()+i-1,c,a.size()+next-1);
            }
            if (b.isFinal(i))
                res.add_final_state(a.size()+i-1);
        }

        return res;
    }

    public static String genOutput (NFA a){
        String str = "";
        str += a.size()+" "+a.symbols()+"\n";
        for (Integer i:a.final_states)
            str+=i+" ";
        str+="\n";

        for (int i=0; i<a.size(); i++)
            for (int c=0; c<a.symbols(); c++)
                if (a.m[i][c] != null && !a.m[i][c].isEmpty())
                    for (Integer next:a.m[i][c])
                        str+=i+" "+(char)(c+'a')+" "+next+"\n";
        return str;
    }

    public static void run_tests(){
        //String[] tests = {"a1.in", "a2.in", "a3.in", "a4.in", "a5.in", "a6.in", "a8.in"};

        String[] tests = {"t.in"};

        for (String test:tests) {

            NFA a = new NFA(test);
            long startTime = System.nanoTime();
            int r = hopcroft(a);
            long endTime = System.nanoTime();

            long duration = (endTime - startTime)/1000000;  //divide by 1000000 to get milliseconds.

            //System.out.println(a);
            //System.out.println(rev(a));
            NFA min = det(rev(det(rev(a))));
            int rp=0;
            if (isTotal(min))
                rp = min.size();
            else rp = min.size()+1;

            //System.out.println(det(rev(det(rev(a)))));

            if (r == rp)
                System.out.println("Test passed [" + duration + " ms] - min states="+r);
            else
                System.out.println("Test " + test + " failed ! r="+r+" vs "+rp);
        }
    }

    public static void gen_tests () {
        NFA a = new NFA("a2.in");
        //System.out.println(a);

        int rep = 10;
        while (rep > 0){
            a = concatenate(a,a);
            rep--;
        }
        System.out.println(genOutput(a));
    }

    // final version
    public static void acm (){

    }

    public static void main (String args[]) throws IOException {

        BufferedReader reader = new BufferedReader(new FileReader("robo.in"));
        Integer test_no = Integer.parseInt(reader.readLine());
        PrintWriter out = new PrintWriter("robo.out");

        while (test_no > 0){
            out.println(hopcroft(new NFA(reader)));
            test_no --;
        }
        reader.close();
        out.close();
        
        //run_tests();
        //gen_tests();

    }
}


/*
class DFA {


    private int state_no, symbol_no;
    int [][] m; // state per symbol,
    HashMap<Integer,HashMap<Integer,List<Integer>>> invm; // invm is the inverse matrix
    List<Integer> final_states;
    boolean isFinal (Integer s){
        return final_states.contains(s);
    }
    public DFA (int state_no, int symbol_no){
        init(state_no,symbol_no);
    }
    private void init (int state_no, int symbol_no){
        this.state_no = state_no;
        this.symbol_no = symbol_no;
        m = new int[state_no][symbol_no];
        invm = new HashMap<Integer,HashMap<Integer,List<Integer>>>();
        final_states = new LinkedList<Integer>();
    }
    public DFA(String filename){
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(filename));
            String line;
            String[] toks;
            line = reader.readLine(); // states and symbols

            toks = line.split("\\s+");
            init(Integer.parseInt(toks[0]), Integer.parseInt(toks[1]));

            line = reader.readLine();
            toks = line.split("\\s+");
            for (String i:toks)
                final_states.add(Integer.parseInt(i));


            while ((line = reader.readLine()) != null)
            {
                toks = line.split("\\s+");
                char c = toks[1].charAt(0);
                Integer s = Integer.parseInt(toks[0]);
                Integer sp = Integer.parseInt(toks[2]);
                m[s][c - 'a'] = sp;
                if (!invm.containsKey(sp)) // no container for symbol
                    invm.put(sp,new HashMap<Integer,List<Integer>>());
                if(!invm.get(sp).containsKey(c - 'a')) // no reverse transition defined
                    invm.get(sp).put(c-'a',new LinkedList<Integer>());
                invm.get(sp).get(c-'a').add(s);

            }
            reader.close();
        }
        catch (Exception e)
        {
            System.err.format("Exception occurred trying to read '%s'.", filename);
            e.printStackTrace();
        }
    }

    public int size (){ return state_no;}
    public int symbols () {return symbol_no;}
    public int final_states(){return final_states.size();}
    public List<Integer> get_nonfinal_states(){
        List<Integer> r = new LinkedList<Integer>();
        for (int i = 0; i<state_no; i++)
            if (!isFinal(i))
                r.add(i);
        return r;
    }
    public List<Integer> get_final_states(){
        return final_states;
    }

    // returns the list of states from which a state in S is reachable via symbol
    public List<Integer> inv (int symbol, List<Integer> S){
        List<Integer> r = new LinkedList<Integer>();
        for (Integer s:S) {
            if (invm.containsKey(s))
                if (invm.get(s).containsKey(symbol))
                    r.addAll(invm.get(s).get(symbol));
        }
        return r;
    }
    @Override
    public String toString(){
        String s = "# ";
        for (int i=0; i<symbol_no; i++)
            s += Character.toString((char)(i + 'a'))+" ";
        s+="\n";
        for (int i=0; i<state_no; i++){
            s += Integer.toString(i)+" ";
            for (int j = 0; j<symbol_no; j++)
                s+= Integer.toString(m[i][j])+" ";
            s += "\n";
        }
        return s;
    }
}
*/