Cod sursa(job #132982)

Utilizator mugurelionutMugurel-Ionut Andreica mugurelionut Data 7 februarie 2008 01:39:43
Problema Tproc Scor Ascuns
Compilator cpp Status done
Runda Marime 8.19 kb
#include <stdio.h>
#include <string.h>

#include <vector>
#include <map>
using namespace std;

#define NMAX 501
#define KMAX 10
#define MMAX 501
#define MAX_STATES 4150
#define INF 666666666

struct tree_node {
	vector<int> *nodes;
	map<int, int> *isInside;
	int nstates;
	int nupnodes;
	int nupstates;
	char state[MAX_STATES][KMAX];
	int smin[MAX_STATES];
	char upstate[MAX_STATES][KMAX];
	int sextra[MAX_STATES];
	map<int, int> *sextraMap;
};

struct tree_node tnode[NMAX];
vector<int> nodes[NMAX], edge[NMAX];
map<int, int> isInside[NMAX], sextraMap[NMAX];
int A[MMAX][MMAX];
char Asellocal[MMAX][MMAX];
char s[KMAX], used[KMAX], viz[NMAX], maxcols;
//int state[KMAX][MAX_STATES][KMAX];
//int smins[KMAX][MAX_STATES][KMAX];
int i, j, k, p, q, N, M, P, localmax;

void readInputData(void)
{
	freopen("tproc.in", "r", stdin);

	scanf("%d %d %d", &N, &M, &maxcols);

	for (i = 1; i <= N; i++)
		edge[i].clear();

	for (k = 1; k < N; k++)
	{
		scanf("%d %d", &i, &j);

		edge[i].push_back(j);
		edge[j].push_back(i);
	}

	for (k = 1; k <= N; k++)
	{
		tnode[k].nodes = &(nodes[k]);
		tnode[k].nodes->clear();

		tnode[k].isInside = &(isInside[k]);
		tnode[k].isInside->clear();

		tnode[k].sextraMap = &(sextraMap[k]);
		tnode[k].sextraMap->clear();

		scanf("%d", &p);

		for (i = 1; i <= p; i++)
		{
			scanf("%d", &j);

			tnode[k].nodes->push_back(j);
		}
	}

	memset(A, 0, sizeof(A));

	scanf("%d", &P);

	for (k = 1; k <= P; k++)
	{
		scanf("%d %d %d", &i, &j, &q);
		A[i][j] = A[j][i] = q;
	}
}

void genStates(char niv, char cmax, int n)
{
	char i;

	if (niv >= tnode[n].nodes->size())
	{
		tnode[n].nstates++;
		memcpy(tnode[n].state[tnode[n].nstates], s, sizeof(s));
		tnode[n].smin[tnode[n].nstates] = 0;

		for (j = 0; j < tnode[n].nodes->size(); j++)
			for (k = j + 1; k < tnode[n].nodes->size(); k++)
				if (s[j] == s[k])
				{
					p = (*tnode[n].nodes)[j];
					q = (*tnode[n].nodes)[k];

					tnode[n].smin[tnode[n].nstates] += A[p][q];
				}
	}
	else
	{
		for (i = 1; i <= cmax + 1 && i <= maxcols; i++)
		{
			s[niv] = i;

			if (i > cmax)
				genStates(niv + 1, cmax + 1, n);
			else
				genStates(niv + 1, cmax, n);
		}
	}
}

char* normalize(char *s, int K)
{
	char i, cnt = 0;

	memset(used, 0, sizeof(used));

	for (i = 0; i < K; i++)
	{
		if (!used[s[i]])
			used[s[i]] = ++cnt;

		s[i] = used[s[i]];
	}

	return s;
}

int hash(char *s, int K)
{
	int i, h = 0;

	for (i = 0; i < K; i++)
		h = (h << 3) + (s[i] - 1);

	return h;
}

inline int getsextra(int n, char* s)
{
	int stnum = (*(tnode[n].sextraMap))[hash(s, tnode[n].nupnodes)];
	return tnode[n].sextra[stnum];
}

// n = nodul din arbore
// t = parintele lui n (in arbore)
void computeCols(int n, int t)
{
	int x, y, p, q, inp, inq, nextra, nextra2, cmax, eq, st, localmin;

	viz[n] = 1;

	// reordoneaza nodurile grafului din cadrul nodului curent al arborelui
	// (primele vor fi nodurile care apar si in cadrul parintelui nodului curent)
	for (x = 0; x < tnode[n].nodes->size(); x++)
		for (y = x + 1; y < tnode[n].nodes->size(); y++)
		{
			p = (*tnode[n].nodes)[x];
			q = (*tnode[n].nodes)[y];

			if ((*tnode[t].isInside)[p])
				inp = 1;
			else
				inp = 0;

			if ((*tnode[t].isInside)[q])
				inq = 1;
			else
				inq = 0;

			if ((!inp && inq) || (inp == inq && p > q))
			{
				(*tnode[n].nodes)[x] = q;
				(*tnode[n].nodes)[y] = p;
			}
		}

	tnode[n].nupnodes = 0;

	for (x = 0; x < tnode[n].nodes->size(); x++)
	{
		p = (*tnode[n].nodes)[x];
		(*tnode[n].isInside)[p] = x + 1;

		if ((*tnode[t].isInside)[p])
			tnode[n].nupnodes++;
	}

	// genereaza toate colorarile posibile cu nodurile grafului din nodul curent al arborelui
	tnode[n].nstates = 0;	
	genStates(0, 0, n);

	localmin = INF;

	for (x = 1; x <= tnode[n].nstates; x++)
	{
		tnode[n].sextra[x] = 0;

		if (tnode[n].smin[x] < localmin)
			localmin = tnode[n].smin[x],
			st = x;
	}

	// selecteaza muchiile ce trebuie adunate in contul lui 'localmin'
	for (x = 0; x < tnode[n].nodes->size(); x++)
		for (y = x + 1; y < tnode[n].nodes->size(); y++)
			if (tnode[n].state[st][x] == tnode[n].state[st][y])
			{
				p = (*tnode[n].nodes)[x];
				q = (*tnode[n].nodes)[y];

				Asellocal[p][q] = Asellocal[q][p] = 1; 
			}

	// adauga la starile generate contributia fiilor nodului curent din arbore

	for (x = 0; x < edge[n].size(); x++)
	{
		y = edge[n][x];

		if (!viz[y])
		{
			computeCols(y, n);

			for (st = 1; st <= tnode[n].nstates; st++)
				if (tnode[n].smin[st] < INF)
				{
					memset(used, 0, sizeof(used));

					for (p = 0; p < tnode[y].nupnodes; p++)
					{
						q = (*tnode[y].nodes)[p];
						q = (*tnode[n].isInside)[q] - 1;
						used[tnode[n].state[st][q]] = 1;
						s[p] = tnode[n].state[st][q];
					}

					nextra = getsextra(y, normalize(s, tnode[y].nupnodes));
					tnode[n].sextra[st] += nextra;
				}
		}
	}

	for (st = 1; st <= tnode[n].nstates; st++)
		if (tnode[n].smin[st] < INF)
		{
			if (tnode[n].sextra[st] < INF)
				tnode[n].smin[st] += tnode[n].sextra[st];
			else
				tnode[n].smin[st] = INF;

			/*
			if (tnode[n].sextra[st] > 0 && tnode[n].sextra[st] < INF)
				printf("!!! nod=%d, st=%d, supl cols=%d\n", n, st, tnode[n].sextra[st]);
			*/

			tnode[n].sextra[st] = 0;
		}

	// pastreaza doar prefixele de 'nupnodes' noduri
	tnode[n].nupstates = 0;

	for (x = 1; x <= tnode[n].nstates; x++)
	{
		memcpy(s, tnode[n].state[x], sizeof(s));
		nextra = tnode[n].smin[x];

		if (tnode[n].smin[x] >= INF)
			nextra = INF;
		else
		{
			for (p = 0; p < tnode[n].nupnodes; p++)
				for (q = p + 1; q < tnode[n].nupnodes; q++)
					if (tnode[n].state[x][p] == tnode[n].state[x][q])
						nextra -= A[(*tnode[n].nodes)[p]][(*tnode[n].nodes)[q]];
		}

		if (tnode[n].nupstates == 0)
		{
			tnode[n].nupstates = 1;
			memcpy(tnode[n].upstate[1], s, sizeof(s));
			tnode[n].sextra[1] = nextra;
		}
		else
		{
			for (eq = 1, y = 0; y < tnode[n].nupnodes; y++)
				if (s[y] != tnode[n].upstate[tnode[n].nupstates][y])
				{
					eq = 0;
					break;
				}

			if (eq)
			{
				if (nextra < tnode[n].sextra[tnode[n].nupstates])
					tnode[n].sextra[tnode[n].nupstates] = nextra;
			}
			else
			{
				tnode[n].nupstates++;
				memcpy(tnode[n].upstate[tnode[n].nupstates], s, sizeof(s));
				tnode[n].sextra[tnode[n].nupstates] = nextra;
			}
		}
	}

	for (x = 1; x <= tnode[n].nupstates; x++)
		(*(tnode[n].sextraMap))[hash(tnode[n].upstate[x], tnode[n].nupnodes)] = x;

	// afisaza niste informatii pentru debug

	/*
	printf("### nod=%d [tata=%d]\n", n, t);
	printf("nnodes=%d, nstates=%d\n", tnode[n].nodes->size(), tnode[n].nstates);
	printf("localmin=%d\n", localmin);
	printf("nupnodes=%d, nupstates=%d\n", tnode[n].nupnodes, tnode[n].nupstates);

	printf("nodes:");
	for (x = 0; x < tnode[n].nodes->size(); x++)
		printf(" %d", (*(tnode[n].nodes))[x]);
	printf("\n");

	printf("|states|\n");
	for (st = 1; st <= tnode[n].nstates; st++)
	{
		if (tnode[n].smins[st] >= INF)
			continue;

		printf("-> state=%d:", st);
		for (p = 0; p < tnode[n].nodes->size(); p++)
			printf(" %d", tnode[n].state[st][p]);

		printf(" : smins=%d\n", tnode[n].smin[st]);
	}

	printf("|upstates|\n");
	for (st = 1; st <= tnode[n].nupstates; st++)
	{
		if (tnode[n].sextra[st] >= INF)
			continue;

		printf("-> upstate=%d:", st);
		for (p = 0; p < tnode[n].nupnodes; p++)
			printf(" %d", tnode[n].upstate[st][p]);
		printf(" : hash=%d, sextra=%d\n", hash(tnode[n].upstate[st], tnode[n].nupnodes), tnode[n].sextra[st]);
	}
	*/
}

void writeOutputData(void)
{
	int smin;

	localmax = 0;

	for (i = 1; i < M; i++)
		for (j = i + 1; j <= M; j++)
			if (Asellocal[i][j])
				localmax += A[i][j];

	printf("* local_smin=%d\n", localmax);

	smin = INF;

	for (i = 1; i <= tnode[1].nstates; i++)
		if (tnode[1].smin[i] < smin)
			smin = tnode[1].smin[i];

	printf("* global_smin=%d\n", smin);

	freopen("tproc.out", "w", stdout);
	printf("%d\n", smin);
}

int main()
{
	readInputData();

	localmax = 0;
	memset(viz, 0, sizeof(viz));
	memset(Asellocal, 0, sizeof(Asellocal));
	computeCols(1, 1);

	writeOutputData();

	return 0;
}