#include <ilcplex/ilocplex.h>

ILOSTLBEGIN

#define pallet 24

typedef IloArray<IloNumArray> IloNumMatrix;
typedef IloArray<IloNumVarArray> IloNumVarMatrix;

int main ()
{
	IloEnv   env;
	try {
		IloModel IP(env);
		IloNumArray u(env, pallet, 0.43,0.66,0.25,0.29,0.59,0.63,0.36,0.60,0.53,0.23,0.89,0.77,0.93,0.17,0.48,0.69,0.56,0.82,0.71,0.34,0.83,0.26,0.51,0.39);

		//ÀÇ»ç°áÁ¤º¯¼ö»ý¼º (À§Ä¡i¿¡¼­ ´Ù¸¥ À§Ä¡·Î ÀÌµ¿ÇÏ´Â °ÍÀ» Ç¥Çö)
		IloNumVarMatrix M(env, pallet);
		for( int i=0; i<pallet; i++ )
		{
			M[i] = IloNumVarArray(env, pallet, 0, 1, IloNumVar::Int);
		}

		//Move out constraint
		//À§Ä¡i¿¡¼­ ´Ù¸¥ À§Ä¡k·Î ÀÌµ¿ÇÏ´Â °ÍÀ» Ç¥Çö (Áßº¹ÀÌµ¿¹æÁö)
		IloExprArray O(env, pallet);
		for(  i=0; i<pallet; i++ ) 
		{
			O[i] = IloExpr(env);
			for( int k=0; k<pallet; k++ )  
			{
				if( i != k ) O[i] += M[i][k];
			}
			IP.add( O[i] <= 1 );
		}		
		
		//Å« ÆÈ·¿ÀÌ ÀÛÀº ÆÈ·ºÀ¸·Î ¿òÁ÷ÀÏ ¼ö ¾ø´Ù.
		for(  i=0; i<pallet; i++ ) 
		{
			O[i] = IloExpr(env);
			for( int k=0; k<pallet; k++ )  
			{
				if( i != k ) O[i] += M[i][k]*u[k];
			}
			IP.add( O[i] >=0 );
		}

		//Flow constraint
		//ÇÑ À§Ä¡¿¡¼­ ´Ù¸¥°÷À¸·Î ÀÌµ¿ÇÑ À§Ä¡¿¡´Â µé¾î¿À´Â °ÍÀ» ¹æÁö
		for(  i=0; i<pallet; i++ ) 
		{
			for( int k=0; k<pallet; k++ )  
			{
				IP.add( O[i] + M[k][i] <= 1 );
			}
		}

		//Utilization constraint
		//ÇÑ À§Ä¡¿¡¼­ÀÇ ÆÈ·¹Æ® Á¡À¯À²Àº 1À» ÃÊ°úÇÒ ¼ö ¾ø´Ù
		for(  i=0; i<pallet; i++ ) 
		{
			IloExpr U(env,u[i]);
			for( int k=0; k<pallet; k++ )  
			{
				if( i != k  ) U += M[k][i]*u[k];
			}
			IP.add( U <= 1 );
		}

		
		//Maximize move out 
		//³ª°£ °¹¼ö¸¸Å­ ºó Àå¼Ò°¡ ´Ã¾î³­´Ù
		IP.add( IloMaximize(env,IloSum(O)) );

		IloCplex cplex(IP);

		//Optimize the problem
		if ( !cplex.solve() )
		{
			env.error() << "Failed to optimize LP" << endl;
			throw(-1);
			
		}

		//Display solution
		for(  i=0; i<pallet; i++ ) 
		{
			for( int k=0; k<pallet; k++ )  
			{
				if( cplex.getValue(M[i][k]) == 1 ) cout<<"move : "<<i<<" --> "<<k<<endl;
			}
		}

		//Display utilization
		for(  i=0; i<pallet; i++ ) 
		{
			IloNum util = u[i];
			cout<<i<<" : "<< util;
			for( int k=0; k<pallet; k++ ) //move out
			{
				if( cplex.getValue(M[i][k]) == 1 ) util -= u[i];
			}
			for(  k=0; k<pallet; k++ ) //move in
			{
				if( cplex.getValue(M[k][i]) == 1 ) util += u[k];
			}
			cout<<" ==> "<<util<<endl;
		}
	int obj = cplex.getObjValue();
	cout << " Z(x)=" << obj << endl;
	cplex.exportModel("pallet consolidation.rlp");

   }
   catch (IloException& e) {
      cerr << "Concert exception caught: " << e << endl;
   }
   catch (...) {
      cerr << "Unknown exception caught" << endl;
   }



   env.end();
   return 0;
}