Cod sursa(job #884966)

Utilizator visanrVisan Radu visanr Data 21 februarie 2013 15:21:19
Problema ADN Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.95 kb
//O prima observatie la problema e ca daca avem cuvinte incluse in alte cuvinte, acelea nu ne mai intereseaza
//Formam un graf, nodurile fiind reprezentate de sirurile din input, iar muchiile cu cost = cat se suprapun cele 2 siruri
//Aflam un lant hamiltonian de cost maxim cu dinamica
//Dp[Conf][i] - costul maxim al unui lant hamiltonian care trece prin nodurile marcate cu 1 in conf si se termina in i

#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

#define Nmax 19
#define Lmax 30010
#define Inf 0x3f3f3f3f

int N, AnsConf, Dp[1 << Nmax][Nmax], PI[Nmax][Lmax];
int Overlap[Nmax][Nmax], Sz[Nmax], Prev[1 << Nmax][Nmax];
bool Out[Nmax];
char S[Nmax][Lmax];

ifstream in("adn.in");
ofstream out("adn.out");

void Build_Prefix(int Idx)
{
    int i, Q = 0;
    PI[Idx][1] = 0;
    for(i = 2; i <= Sz[Idx]; ++ i)
    {
        while(Q && S[Idx][Q + 1] != S[Idx][i]) Q = PI[Idx][Q];
        if(S[Idx][Q + 1] == S[Idx][i]) Q ++;
        PI[Idx][i] = Q;
    }
}

int GetOverlap(int A, int B)
{
    int i, Q = 0;
    for(i = 1; i <= Sz[A]; ++ i)
    {
        while(Q && S[B][Q + 1] != S[A][i]) Q = PI[B][Q];
        if(S[B][Q + 1] == S[A][i]) Q ++;
        if(Q == Sz[B])
            return Q;
    }
    return Q;
}

void Reconstruct(int Conf, int Pos)
{
    if(Conf == (1 << Pos))
    {
        out << S[Pos] + 1;
        return ;
    }
    Reconstruct(Conf ^ (1 << Pos), Prev[Conf][Pos]);
    out << S[Pos] + 1 - Overlap[Prev[Conf][Pos]][Pos];
}

int main()
{
    in >> N;
    for(int i = 0; i < N; ++ i)
    {
        in >> (S[i] + 1);
        Sz[i] = strlen(S[i] + 1);
        Build_Prefix(i);
    }
    for(int i = 0; i < N; ++ i)
        for(int j = i + 1; j < N; ++ j)
        {
            int FirstOver = GetOverlap(i, j), SecondOver = GetOverlap(j, i);
            Overlap[i][j] = -FirstOver;
            Overlap[j][i] = -SecondOver;
            if(FirstOver == Sz[j]) Out[j] = 1;
            if(SecondOver == Sz[i] && FirstOver != Sz[j]) Out[i] = 1;
        }
    memset(Dp, Inf, sizeof(Dp));
    for(int i = 0; i < N; ++ i)
        if(Out[i] == 0)
        {
            Dp[1 << i][i] = 0;
            AnsConf ^= (1 << i);
        }
    for(int Conf = 1; Conf < (1 << N); ++ Conf)
        for(int i = 0; i < N; i++)
            if(Out[i] == 0 && Dp[Conf][i] != Inf && (Conf & (1 << i)))
                for(int j = 0; j < N; j++)
                    if(!Out[j] && !(Conf & (1 << j)))
                        if(Dp[Conf ^ (1 << j)][j] > Dp[Conf][i] + Overlap[i][j])
                        {
                            Dp[Conf ^ (1 << j)][j] = Dp[Conf][i] + Overlap[i][j];
                            Prev[Conf ^ (1 << j)][j] = i;
                        }
    int StartPos = 0;
    for(int i = 0; i < N; i++)
        if(Dp[AnsConf][i] < Dp[AnsConf][StartPos])
            StartPos = i;
    Reconstruct(AnsConf, StartPos);
    return 0;
}