#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.23, 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( int 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 );
		}

		//Flow constraint
		//ÇÑ À§Ä¡¿¡¼­ ´Ù¸¥°÷À¸·Î ÀÌµ¿ÇÑ À§Ä¡¿¡´Â µé¾î¿À´Â °ÍÀ» ¹æÁö
		for( int i=0; i<pallet; i++ ) 
		{
			for( int k=0; k<pallet; k++ )  
			{
				IP.add( O[i] + M[k][i] <= 1 );
			}
		}

		//Utilization constraint
		//ÇÑ À§Ä¡¿¡¼­ÀÇ ÆÈ·¹Æ® Á¡À¯À²Àº 1À» ÃÊ°úÇÒ ¼ö ¾ø´Ù
		for( int 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( int 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( int 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( int k=0; k<pallet; k++ ) //move in
			{
				if( cplex.getValue(M[k][i]) == 1 ) util += u[k];
			}
			cout<<" ==> "<<util<<endl;
		}

   }
   catch (IloException& e) {
      cerr << "Concert exception caught: " << e << endl;
   }
   catch (...) {
      cerr << "Unknown exception caught" << endl;
   }
   env.end();
   return 0;
}