import java.util.Arrays;

/**
 *  This is a stub, you should rename the file to Party.java 
 *
 * Party is a class to solve the party problem in general (not just for trees).
*
* The party problem takes a graph as input.
* A vertex of this graph models a person.
* Each vertex has a positive weight modelling the Person's fun factor.
* An edge between two vertices indicates an incompatibility to organise a party : e.g. dislike, one person is a direct boss of the other etc.
*
* A Party is a subset of the vertices that are pairwise not connected by an edge (an independent set in graph jargon).
* The sum of the fun factors of guests (member of the subset) evaluates the quality of the party.
* The higher it is, the best it is.
* 
* The Party Problem consists in computing the best possible party value / computing a solution with the best party value.
*
* In graph parlance, this problem is known as Maximum Weighted Independent Set. It is known to be NP-complete for general graphs as inputs.
* This means that it is very unlikely that a polynomial time (in the size of the input graph) algorithm exists.
*
* This class proposes an exponential time algorithm that proceeds as follows.
* It initialises the search with a greedy method to yield a lower bound on the best Party.
* It proceeds with a backtracking method to search through (partial) parties.
* A search may be cut off if :
* adding the current vertex would not yield a Party (the added vertex is a neighbour of a vertex already present) above in the search; or,
* adding all remaining vertices would not yield a Party better than the currently known best one (just pretend all remaining vertices would be added).
* 
* @author Florent Madelaine
* 
*/

public class Party {

    // graphe (il faut des 0 et des 1) pour arêtes pas arêtes.
    private int[][] graphe;

    // entier positifs ce sont les fun factors
    private int[] poids;

    // pour marquer les éléments visités.
    private boolean[] marked;

    // pour stocker la solution partielle en cours de fabrication
    private int[] psolution;

    // valeur de la meilleur fête.
    private int best;

    // meilleure solution jusqu'à présent
    private int[] bestParty;

    /**
     * getter
     *
     * @return the value of the best known Party.
     */
    public int getBest(){
	return this.best;
    }

    /**
     * getter
     *
     * @return the value of the best known Party.
     */
    public int[] getBestParty(){
	return this.bestParty;
    }

    /**
     * 
     * @return a String representing the current state of the Party object
     */
    public String toString(){
	String out = "";
	out+="poids: " + Arrays.toString(this.poids)+"\n";
	out+="graphe:\n"; //+ Arrays.deepToString(this.graphe)+"\n";
	for(int i = 0;  i < this.graphe.length; i++){
	    out+="\t" + Arrays.toString(graphe[i])+"\n";
	}	    
	out+="marked: "+ Arrays.toString(this.marked)+"\n";
	out+="psolution: " + Arrays.toString(this.psolution)+"\n";
	out+="bestParty: " + Arrays.toString(this.bestParty)+"\n";
	out+="best: "+ this.best+"\n";
	return out;
    }
    
    /**
     * constructor
     *
     * @param graph a 0/1 (square) adjacency matrix
     * @param poids an array of int representing the weights of the vertices   
     * @throws IllegalArgumentException if the matrix is not square or array of weights of inconsitent size with matrix.
     */
    public Party(int[][] graphe, int[] poids){
	int n = graphe.length;
	if ((graphe[0].length != graphe.length) || (graphe.length != poids.length)) throw new IllegalArgumentException("graphe should be a square matrix of the same side as the length of poids.");
	
	this.graphe=graphe;
	this.poids=poids;

	this.marked = new boolean[n];
	this.psolution = new int[n];
	this.best=0;
	this.bestParty= new int[n];
    }

    /**
     * getter
     *
     * @return the value of the current party (psolution).
     */
    public int getCurrentPartyValue(){
	int res = 0;
	for(int i = 0;  i < this.psolution.length; i++){
	    res+= psolution[i]*poids[i];
	}

	return res;
    }

    /**
     * getter
     *
     * @param j an index in the solution that should represent the index to the left of which we have stored a partial solution. 
     * @return the max value that the current party (psolution) could possibly reach (simulate adding vertices after j)
     */
    public int getUpperBoundCurrentPartyValue(int j){
	// j should be an index of psolution
	int res = 0;
	for(int i = 0; i < this.psolution.length; i++){
	    if (i<j){
		res+= psolution[i]*poids[i];
	    }
	    else{
		// à partir de j on compte le poids forcément.
		res+= poids[i];
	    }
	}
	return res;
    }

    /**
     * Method to compute a first Party with a greedy method
     *
     * It sets bestParty to a bitmap representing a legal Party in a greedy fashion
     * It updates best to be the value of this computed party
     */
    public void greedy(){
	// work here
    }

    /**
     * Method to search and compute the best Party using bactracking.
     * @param next represent the integer from which psolution (the current partial solution under study) should be extended
     *
     * If next is beyond psolution size, psolution is a complete candidate solution to the Party problem.
     * The method should update bestParty with this solution if it is better.
     * (you should clone the array to avoid problems).
     *
     * otherwise, if next falls within the bitmap, it will search the two cases one after the other
     * adding the vertex at index next to the psolution (case1)
     * or not adding this vertex (case2).
     * If both cases are legal / can not be removed from the search, it proceeds by caling backtrack with parameter next+1
     */
    public void backtrack(int next){
	if (next >= psolution.length)
	    {// fini de construire une solution
		
	    }
	else{
	    // cas value=1 d'abord.
	    int value =1;
	    // mise à jour solution partielle si possible
	    boolean ajoute = true;

	    // TO DO : tester si ajoute est OK sinon mettre ajoute à faux
	    
	    if (ajoute){
		psolution[next]=value;
		
		// TO DO : on pourrait peut-être s'arrêter?
		backtrack(next+1);
		
	    }
	    // cas value=0 ensuite
	    value=0

		// TO DO

	}

    }

    
    public static void main(String[] args) {

	// A B C forment un triangle, E et D voisins de C.
	// poids 4, 5, 2, 6, 1.
	
	int[][] graphe = {
	    { 0, 1, 1, 0, 0},
	    { 1, 0, 1, 0, 0},
	    { 1, 1, 0, 1, 1},
	    { 0, 0, 1, 0, 0},
	    { 0, 0, 1, 0, 0}
	};

	int [] poids = {4,5,2,6,1};

	Party p = new Party(graphe, poids);

	p.greedy();
	System.out.println(Arrays.toString(p.getBestParty())); // Display the string.
	System.out.println(p.getBest()); // Display the best Pary

	System.out.println(p);
    }
}


