Cod sursa(job #979032)

Utilizator mitrutstrutMitrea Andrei Ionut mitrutstrut Data 31 iulie 2013 10:27:16
Problema Tproc Scor 0
Compilator cpp Status done
Runda Lista lui wefgef Marime 10.01 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;
}