Cod sursa(job #82392)

Utilizator MariusMarius Stroe Marius Data 6 septembrie 2007 20:10:17
Problema Dame Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.83 kb
#include <stdio.h>
#include <memory.h>
#include <time.h>
#include <stdlib.h>

const char iname[] = "dame.in";
const char oname[] = "dame.out";

#define MAXN  1007


void print(int n, int queen[])
{
	FILE *fo = fopen(oname, "w");

	fprintf(fo, "%d\n", n);
	for (int i = 1; i <= n; ++ i)
		fprintf(fo, "%d %d\n", i, queen[i]);
	fclose(fo);
}

void perform_swap(int i, int j, int n, int queen[], int dn[], int dp[])
{
	int temp;

	dn[i + queen[i]] --;
	dp[i - queen[i] + n] --;
	dn[j + queen[j]] --;
	dp[j - queen[j] + n] --;

	temp = queen[i], queen[i] = queen[j], queen[j] = temp;
	dn[i + queen[i]] ++;
	dp[i - queen[i] + n] ++;
	dn[j + queen[j]] ++;
	dp[j - queen[j] + n] ++;
}

int swap(int i, int j, int n, int queen[], int dn[], int dp[], int collisions)
{
	if ((i + queen[i] == j + queen[j]) || (i - queen[i] == j - queen[j]))
		return collisions;

	int tcollisions = collisions;

	if (dn[i + queen[i]] >= 2)
		tcollisions --;
	if (dp[i - queen[i] + n] >= 2)
		tcollisions --;
	if (dn[j + queen[j]] >= 2)
		tcollisions --;
	if (dp[j - queen[j] + n] >= 2)
		tcollisions --;

	if (dn[j + queen[i]] >= 1)
		tcollisions ++;
	if (dp[j - queen[i] + n] >= 1)
		tcollisions ++;
	if (dn[i + queen[j]] >= 1)
		tcollisions ++;
	if (dp[i - queen[j] + n] >= 1)
		tcollisions ++;

	return tcollisions;
}

int compute_attacks(int n, int queen[], int dn[], int dp[], int attack[])
{
	int number_of_attacks = 0;

	for (int i = 1; i <= n; ++ i) {
		if (dn[i + queen[i]] >= 2)
			attack[number_of_attacks ++] = i;
		if (dp[i - queen[i] + n] >= 2)
			attack[number_of_attacks ++] = i;
	}
	return number_of_attacks;
}

int compute_collisions(int n, int queen[], int dn[], int dp[])
{
	int collisions = 0;

	for (int i = 1; i <= n; ++ i) {
		dn[i + queen[i]] ++;
		dp[i - queen[i] + n] ++;
	}
	for (int i = 2; i <= 2 * n; ++ i) {
		if (dn[i] >= 2)
			collisions += dn[i] - 1;
	}
	for (int i = 1 - n; i <= n - 1; ++ i) {
		if (dp[i + n] >= 2)
			collisions += dp[i + n] - 1;
	}
	return collisions;
}

int main(void)
{
	srand((unsigned)time(0));

	int n;

	FILE *fi = fopen(iname, "r");

	fscanf(fi, "%d", &n);
	fclose(fi);		

	/* queen search */ 
	int queen[MAXN];
	int dn[MAXN << 1];	/*   2, .., 2*n */
	int dp[MAXN << 1];	/* 1-n, .., n-1 */
	int attack[MAXN];
	int used_column[MAXN];
	int limit, collisions, number_of_attacks, loopcount;

	int C2 = 32;
	double C1 = 0.45;

	if (n == 2) {
		queen[1] = 1, print(1, queen);
		return 0;
	}
	if (n == 3) {
		queen[1] = 1, queen[2] = 3, print(2, queen);
		return 0;
	}

	do {
		memset(used_column, 0, sizeof(used_column));
		memset(dn, 0, sizeof(dn));
		memset(dp, 0, sizeof(dp));
		
		/* a random permutation of 1,..,n */
		for (int i = 1; i <= n; ++ i) {
			int count = rand() % (n-i+1);
			for (int j = 1; j <= n; ++ j) {
				if (used_column[j] == 0) {
					if (count == 0) {
						queen[i] = j, used_column[j] = 1;
						break ;
					} else
						count --;
				}
			}
		}
		/* compute */
		collisions = compute_collisions(n, queen, dn, dp);
		limit = C1 * collisions;
		number_of_attacks = compute_attacks(n, queen, dn, dp, attack);
		loopcount = 0;
		/* search */
		while ((collisions > 0) && (loopcount <= C2 * n)) {
			for (int k = 0; k < number_of_attacks; ++ k) {
				int i = attack[k];
				int j = (rand() % n) + 1;
				int tcollisions = swap(i, j, n, queen, dn, dp, collisions);
				if (tcollisions < collisions) {
					collisions = tcollisions;
					perform_swap(i, j, n, queen, dn, dp);
					if (collisions == 0) {
						print(n, queen);
						return 0;
					} else if (collisions < limit) {
						limit = C1 * collisions;
						number_of_attacks = compute_attacks(n, queen, dn, dp, attack);
					}
				}
			}
			loopcount += number_of_attacks;
		}
	} while (collisions > 0) ;
	
	print(n, queen);
	
	return 0;
}