// Mugurel Ionut Andreica #include #include #include #include #include using namespace std; #define LOCAL 0 #define NUM_LOCAL_GRAPHS 10 #define DEBUG 0 #define NMAX 51 class MersenneTwister { private: // Period parameters static const int N = 624; static const int M = 397; static const int MATRIX_A = 0x9908b0df; // private static final * constant vector a static const int UPPER_MASK = 0x80000000; // most significant w-r bits static const int LOWER_MASK = 0x7fffffff; // least significant r bits // Tempering parameters static const int TEMPERING_MASK_B = 0x9d2c5680; static const int TEMPERING_MASK_C = 0xefc60000; int* mt; // the array for the state vector int mti; // mti==N+1 means mt[N] is not initialized int* mag01; // a good initial seed (of int size, though stored in a long) //private static final long GOOD_SEED = 4357; public: /** * Constructor using a given seed. Though you pass this seed in * as a long, it's best to make sure it's actually an integer. */ MersenneTwister(int seed) { setSeed(seed); } /** * Initalize the pseudo random number generator. Don't * pass in a long that's bigger than an int (Mersenne Twister * only uses the first 32 bits for its seed). */ void setSeed(long seed) { mt = new int[N]; mag01 = new int[2]; mag01[0] = 0x0; mag01[1] = MATRIX_A; mt[0]= (int)(seed & 0xffffffff); mt[0] = (int) seed; for (mti=1; mti> 30)) + mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ // mt[mti] &= 0xffffffff; /* for >32 bit machines */ } } /** * Returns an integer with bits bits filled with a random number. */ int next(int bits) { int y; if (mti >= N) { // generate N words at one time int kk; int* mt = this->mt; // locals are slightly faster int* mag01 = this->mag01; // locals are slightly faster for (kk = 0; kk < N - M; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); mt[kk] = mt[kk+M] ^ (((unsigned int) y) >> 1) ^ mag01[y & 0x1]; } for (; kk < N-1; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); mt[kk] = mt[kk+(M-N)] ^ (((unsigned int) y) >> 1) ^ mag01[y & 0x1]; } y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); mt[N-1] = mt[M-1] ^ (((unsigned int) y) >> 1) ^ mag01[y & 0x1]; mti = 0; } y = mt[mti++]; y ^= ((unsigned int) y) >> 11; // TEMPERING_SHIFT_U(y) y ^= (y << 7) & TEMPERING_MASK_B; // TEMPERING_SHIFT_S(y) y ^= (y << 15) & TEMPERING_MASK_C; // TEMPERING_SHIFT_T(y) y ^= (((unsigned int) y) >> 18); // TEMPERING_SHIFT_L(y) int ret = ((unsigned int) y) >> (32 - bits); return ret; } /** A bug fix for versions of JDK 1.1 and below. JDK 1.2 fixes this for us, but what the heck. */ double nextDouble() { double d = (((long long)next(26) << 27) + next(27)) / (double)(1LL << 53); return d; } }; int A[NMAX][NMAX]; int N; void ReadInput() { int i, j; scanf("%d", &N); for (i = 1; i <= N; i++) { for (j = 1; j <= N; j++) scanf("%d", &A[i][j]); } } void WriteMove(int x, int y) { if (LOCAL) return; printf("%d %d\n", x, y); fflush(stdout); } int LOCAL_STRATEGY; MersenneTwister* LOCAL_MT; void ReadMove(int cnode, int& x, int&y) { if (LOCAL) { vector > outedges; for (x = 1; x <= N; x++) if (A[cnode][x] > 0) outedges.push_back(make_pair(A[cnode][x], x)); sort(outedges.begin(), outedges.end()); if (outedges.size() == 0) exit(666); x = cnode; if (LOCAL_STRATEGY == -2) { // MIN y = outedges[0].second; } else if (LOCAL_STRATEGY == -1) { // MAX y = outedges[outedges.size() - 1].second; } else { // RANDOM y = LOCAL_MT->next(10) % outedges.size(); } } else { scanf("%d %d", &x, &y); } } int FS; void MaxGreedy() { int x = 0, y = 0, z, i, j, vmax = 0, dif, a, b, max_strategy = 1; for (i = 1; i <= N; i++) for (j = 1; j <= N; j++) if (A[i][j] > vmax) { vmax = A[i][j]; x = i; y = j; } FS = 0; WriteMove(x, y); FS += A[x][y]; A[x][y] = 0; while (1) { int cnode = y; for (x = 1; x <= N; x++) if (A[cnode][x]) break; if (x > N) break; ReadMove(cnode, a, b); FS -= A[a][b]; if (max_strategy) { for (x = 1; x <= N; x++) if (A[a][b] < A[cnode][x]) { max_strategy = 0; break; } } A[a][b] = 0; if (max_strategy) { // Choose a move which maximizes the difference between the score of the move and the score of the next move, made by the opponent. int difmax; for (y = difmax = 0, x = 1; x <= N; x++) if (A[b][x] > 0) { for (vmax = 0, z = 1; z <= N; z++) if (A[x][z] > vmax) vmax = A[x][z]; dif = A[b][x] - vmax; if (y == 0 || dif > difmax) { y = x; difmax = dif; } } } else { // Choose a move which maximizes the expected difference between the score of the move and the score of the next move, made by the opponent. double difmax; for (y = 0, difmax = 0.0, x = 1; x <= N; x++) if (A[b][x] > 0) { double sum = 0.0; int cnt = 0; for (z = 1; z <= N; z++) if (A[x][z] > 0) { sum += A[x][z]; cnt++; } double dif; if (cnt == 0) dif = A[b][x]; else dif = A[b][x] - sum / cnt; if (y == 0 || dif > difmax) { y = x; difmax = dif; } } } if (y == 0) break; WriteMove(b, y); FS += A[b][y]; A[b][y] = 0; } fprintf(stderr, "FS=%d\n", FS); } void Solve() { MaxGreedy(); } char used[NMAX * NMAX]; void GenerateGraph(MersenneTwister& mt) { N = 50; int i, j, VMAX = N * (N - 1); memset(used, 0, sizeof(used)); for (i = 1; i <= N; i++) for (j = 1; j <= N; j++) if (i == j) A[i][j] = 0; else { while (1) { A[i][j] = 1 + (mt.next(20) % VMAX); if (!used[A[i][j]]) break; } used[A[i][j]] = 1; } } int main() { if (LOCAL) { double total_score = 0.0; MersenneTwister mt(987654321); for (int g = 0; g < NUM_LOCAL_GRAPHS; g++) { // MAX mt.setSeed(1000001 * g + 999997); GenerateGraph(mt); LOCAL_STRATEGY = -1; Solve(); total_score += FS; fprintf(stderr, "AVG_SCORE=%.2lf\n", total_score / (2 * g + 1)); // RANDOM mt.setSeed(1000001 * g + 999997); GenerateGraph(mt); LOCAL_STRATEGY = 232823283; LOCAL_MT = new MersenneTwister(LOCAL_STRATEGY); Solve(); total_score += FS; fprintf(stderr, "AVG_SCORE=%.2lf\n", total_score / (2 * g + 2)); } } else { ReadInput(); Solve(); } return 0; }