Submission #2078990


Source Code Expand

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(n);++i)
#define ALL(A) A.begin(), A.end()
#define INF 1<<28

using namespace std;

typedef long long ll;
typedef pair<int, int> P;
const int MAX_N = 2001;
const int MAX_H = 50;
const int MAX_W = 50;

const string dir = "URDL";
const int dr[4] = {-1, 0, 1, 0};
const int dc[4] = { 0, 1, 0,-1};

int H, W, K, sr, sc;
int N;
int fr[MAX_N], fc[MAX_N], F[MAX_N], D[MAX_N];
vector<string> grid;

int toFood[MAX_N];		// 犬の位置から各フードの位置までの距離
int dist[MAX_N][MAX_N];	// 各フード間の距離
int visit[MAX_H][MAX_W];		// 訪問フラグ


#if SUBMIT
const int64_t CYCLES_PER_SEC = 2800000000;
#else
const int64_t CYCLES_PER_SEC = 2400000000;
#endif

const double TIME_LIMIT = 9.5;
const int MAX_V = 200;
const int MAX_HASH_SIZE = 5*(int)1e7;
const int MAX_BEAM_DEPTH = 200;
const int MAX_BEAM_WIDTH = 100;

struct Timer {
	int64_t start;
	int counter;
	double t;

	Timer() {
		reset();
	}

	void plus(double a){
		start -= a * CYCLES_PER_SEC;
	}

	int64_t getCycle() {
		uint32_t low, high;
		__asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
		return ((int64_t)low) | ((int64_t)high << 32);
	}

	void reset(){
		counter = 0;
		start = getCycle();
		t = 0.0;
	}

	double get(){
		return t = (double)(getCycle() - start) / CYCLES_PER_SEC;
	}
};

unsigned Rand(){ 
	static unsigned x=123456789;
	static unsigned y=362436069;
	static unsigned z=521288629;
	static unsigned w=88675123; 
	unsigned t=x^(x<<11);
	x=y; y=z; z=w;
 
	return w=(w^(w>>19))^(t^(t>>8));
}

struct NODE{
	int score;
	vector<int> perm;
	NODE(int _score, vector<int> _perm):score(_score),perm(_perm){}
	
	bool operator>(const NODE& node) const{
		return score > node.score;
	}
};

namespace Pool{
	int Q_size[MAX_BEAM_DEPTH + 1];
	NODE* Q[MAX_BEAM_DEPTH + 1][MAX_BEAM_WIDTH * MAX_BEAM_WIDTH];

	void initQueue(int sz){
		for (int i = 0; i < sz; ++i) Q_size[i] = 0;
	}

	void pushQ(int i, NODE* x){
		Q[i][Q_size[i]++] = x;
	}
};

struct NODECompare{
	bool operator()(NODE* n1, NODE* n2) const{
		return *n1 > *n2;
	}
};


bool table[MAX_HASH_SIZE];

void calcDist(int cr, int cc){
	memset(visit, -1, sizeof(visit));
	queue<P> que;
	que.push(P(cr * W + cc, 0));
	while(!que.empty()){
		P curr = que.front(); que.pop();
		cr = curr.first / W;
		cc = curr.first % W;
		int d = curr.second;
		if (visit[cr][cc] == -1){
			visit[cr][cc] = d;
			rep (k, 4){
				int nr = cr + dr[k];
				int nc = cc + dc[k];
				if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;
				if (grid[nr][nc] == '#') continue;
				if (visit[nr][nc] == -1){
					que.push(P(nr * W + nc, d + 1));
				} // end if
			} // end rep
		} // end if
	}
}	

void calctoFood(void){
	calcDist(sr, sc);
	rep (i, N){
		toFood[i] = visit[fr[i]][fc[i]];
	} // end rep
}			

void calcF2F(void){
	rep (i, N){
		calcDist(fr[i], fc[i]);
		rep (j, N){
			dist[i][j] = visit[fr[j]][fc[j]];
		} // end rep
	} // end rep
}

void disp_grid(void){
	rep (i, H){
		rep (j, W){
			cerr << grid[i][j];
		} // end rep
		cerr << endl;
	} // end rep
}

void dispVisit(void){
	rep (i, H){
		rep (j, W){
			cerr << setw(2) << visit[i][j];
		} // end rep
		cerr << endl;
	} // end rep
}

class BeamSearch{
public:
	Timer timer;
 	double startTime;
	double endTime;
	double currentTime;

	vector<int> hillClimbing(void){
		startTime = timer.t;
		endTime = TIME_LIMIT;
		initZobrit();
		vector<int> perm = init_perm();
		vector<int> best = perm;
		int bestScore = calcScore(perm);
		int iter = 0;
		while((currentTime = timer.get()) < endTime){
			int i = Rand() % N;
			int j = Rand() % (N - 1);
			if (j == i) ++j;
			swap(perm[i], perm[j]);
			int h = hash(perm);
			if (table[h]){
				swap(perm[i], perm[j]);
				continue;
			} // end if
			table[h] |= true;
			int score = calcScore(perm);
			if (bestScore < score){
				bestScore = score;
				best = perm;
			}else{
				swap(perm[i], perm[j]);
			} // end if
		} // end while
		return best;
	}

	vector<int> beam(void){
		startTime = timer.t;
		endTime = TIME_LIMIT;
		initZobrit();
		Pool::initQueue(MAX_BEAM_DEPTH + 1);
		int bestScore = 0;
		vector<int> best; best.clear();
		rep (i, MAX_BEAM_WIDTH){
			vector<int> curr = init_perm();
			int score = calcScore(curr);
			if (score == -1) continue;
			int h = hash(curr);
			if (table[h]){
				continue;
			} // end if
			table[h] |= true;
			NODE* origin = new NODE(score, curr);
			if (score > bestScore){
				bestScore = score;
				best = curr;
			} // end if
		} // end rep

		int lim = MAX_BEAM_WIDTH;
		int iter = 0;		
		for (int step = 0; step < MAX_BEAM_DEPTH; ++step){
			++iter;
			if (Pool::Q_size[step] == 0) break;
			sort(Pool::Q[step],Pool::Q[step] + Pool::Q_size[step], NODECompare());
			
			if ((currentTime = timer.get()) >= endTime){
				break;
			} // end if

			int lookUpSize = min(Pool::Q_size[step], lim);
			for (int qIdx = 0; qIdx < lookUpSize; ++qIdx){
				if ((currentTime = timer.get()) >= endTime){
					break;
				} // end if
				auto q = Pool::Q[step][qIdx];
				for (int next = 0; next < lim; ++next){
					int score = q->score;
					vector<int> perm = q->perm;
					int from = Rand() % N;
					int   to = Rand() % (N - 1);
					if (from == to) ++to;
					swap(perm[from], perm[to]);
					int h = hash(perm);
					if (table[h]) continue;
					table[h] |= true;
					int nextScore = calcScore(perm);
					NODE* cand = new NODE(nextScore, perm);
					if (bestScore < nextScore){
						bestScore = nextScore;
						best = perm;
					} // end if
					Pool::pushQ(step + 1, cand);
					if ((currentTime = timer.get()) >= endTime){
						break;
					} // end if
				} // end for
			} // end for
		} // end for
		cerr << "iter: " << iter << ' ';

		return best;
	}

private:
	vector<int> random_table;

	int calcScore(vector<int> perm){
		int sumt = 0;
		int score = 0;
		int t = toFood[perm[0]];
		if (t == -1){
			return -1;
		} // end if
		sumt += t;
		score += max(0, F[perm[0]] - sumt * D[perm[0]]);
		for (int i = 1; i < N; ++i){
			int t = dist[perm[i-1]][perm[i]];
			if (t == -1){
				return -1;
			} // end if
			sumt += t;
			score += max(0, F[perm[i]] - sumt * D[perm[i]]);
		} // end for
		return score; 
	}

	vector<int> init_perm(void){
		vector<int> perm(N, 0);
		rep (i, N) perm[i] = i;
		for (int i = 0; i < N - 1; ++i){
			int j = Rand() % (N - i) + i;
			swap (perm[i], perm[j]);
		} // end for
		return perm;
	}

	void initZobrit(void){
		random_table.clear();
		random_table.resize(N*N, 0);
		for (int i = 0; i < N*N; ++i) random_table[i] = Rand() % MAX_HASH_SIZE;
	}

	int hash(vector<int> perm){
		int h = 0;
		for (int i = 0; i < N; ++i){
			h = h ^ random_table[i + N * perm[i]];
		} // end for
		return h % MAX_HASH_SIZE;
	}
};

string from2to(int spos, int epos){
	string res = "";
	int cr = epos / W;
	int cc = epos % W;
	while(cr * W + cc != spos){
		int curr = visit[cr][cc];
		for (int k = 0; k < 4; ++k){
			int nr = cr + dr[k];
			int nc = cc + dc[k];
			if (nr < 0 || nr >= H || nc < 0 || nc >= W) continue;
			if (visit[nr][nc] == -1) continue;
			if (visit[nr][nc] + 1 == curr){
				res += dir[(k + 2) % 4];
				cr = nr;
				cc = nc;
				break;
			} // end if
		} // end for
	} // end while
	reverse(ALL(res));

	return res;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	memset(fr, 0, sizeof(fr));
	memset(fc, 0, sizeof(fc));
	memset(F, 0, sizeof(F));
	memset(D, 0, sizeof(D));
	memset(toFood, -1, sizeof(toFood));
	memset(dist, -1, sizeof(dist));
	grid.clear();
	cin >> H >> W >> K >> sr >> sc;
	--sr;
	--sc;
	grid.resize(H, string(W, '.'));
	rep (i, H){
		cin >> grid[i];
	} // end rep

	cin >> N;
	rep (i, N){
		cin >> fr[i] >> fc[i] >> F[i] >> D[i];
		--fr[i];
		--fc[i];
//		grid[fr[i]][fc[i]] = (char)('0' + i);
	} // end rep

//	grid[sr][sc] = 'S';

#if DEBUG	
	disp_grid();
#endif
	calctoFood();

#if DEBUG
	rep (i, N){
		cerr << toFood[i] << ' ';
	} //end rep
	cerr << endl;
#endif
	calcF2F();
#if DEBUG
	rep (i, N){
		rep (j, N){
			cerr << dist[i][j] << ' ';
		} // end rep
		cerr << endl;
	} // end rep
#endif
	BeamSearch BS;
//	vector<int> res = BS.beam();
	vector<int> res = BS.hillClimbing();

#if DEBUG
	rep (i, (int)res.size()){
		cerr << res[i] << ' ';
	} // end rep
	cerr << endl;
#endif
	calctoFood();
	string ans = "";
#if DEBUG
	dispVisit();
#endif
	string curr = from2to(sr * W + sc, fr[res[0]] * W + fc[res[0]]);
	ans += curr;

	for (int i = 0; i < (int)res.size() - 1; ++i){
		calcDist(fr[res[i]], fc[res[i]]);
		string curr = from2to(fr[res[i]] * W + fc[res[i]], fr[res[i+1]] * W + fc[res[i+1]]);
		ans += curr;
	} // end for


	if (ans.length() > K){
		ans = ans.substr(0, K);
	}else{
		while(ans.length() < K){
			ans += '-';
		} // end while
	} // end if

	cout << ans << endl;

	return 0;
}

Submission Info

Submission Time
Task B - Food Collector
User ty70
Language C++14 (GCC 5.4.1)
Score 9593
Code Size 9130 Byte
Status AC
Exec Time 8256 ms
Memory 69376 KB

Judge Result

Set Name test_01 test_02 test_03 test_04 test_05 test_06 test_07 test_08 test_09 test_10
Score / Max Score 1191 / 20000 1033 / 20000 991 / 20000 609 / 20000 1056 / 20000 1262 / 20000 916 / 20000 821 / 20000 632 / 20000 1082 / 20000
Status
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
Set Name Test Cases
test_01 subtask_01_01.txt
test_02 subtask_01_02.txt
test_03 subtask_01_03.txt
test_04 subtask_01_04.txt
test_05 subtask_01_05.txt
test_06 subtask_01_06.txt
test_07 subtask_01_07.txt
test_08 subtask_01_08.txt
test_09 subtask_01_09.txt
test_10 subtask_01_10.txt
Case Name Status Exec Time Memory
subtask_01_01.txt AC 8199 ms 67584 KB
subtask_01_02.txt AC 8256 ms 69376 KB
subtask_01_03.txt AC 8229 ms 67968 KB
subtask_01_04.txt AC 8183 ms 66560 KB
subtask_01_05.txt AC 8209 ms 67584 KB
subtask_01_06.txt AC 8236 ms 68736 KB
subtask_01_07.txt AC 8226 ms 68096 KB
subtask_01_08.txt AC 8201 ms 67072 KB
subtask_01_09.txt AC 8178 ms 66560 KB
subtask_01_10.txt AC 8224 ms 68352 KB