Cod sursa(job #3124791)

Utilizator CelestinNegraru Celestin Celestin Data 30 aprilie 2023 01:42:02
Problema ADN Scor 70
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 6.27 kb
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <stack>
#include <string>
#define nmax 18
#define smax 30005
#define INF 0x3f3f3f3f
using namespace std;
ifstream f;
ofstream g;
vector<string> siruri;
vector<pair<int,int>> V[nmax];
vector<int> V2[nmax];
stack<int> stiva;
int n,s,dp[(1<<nmax)+1][nmax][2],mat_ad[nmax][nmax];
pair<pair<int,int>,bool> parent[(1<<nmax)+1][nmax];
void precompute(string a,int lps[])
{
    int i=1,len=0;
    int m=a.size();
    lps[0]=0;
    while(i<m)
    {
        if(a[i]==a[len]){
            len++;
            lps[i]=len;
            i++;
        }
        else{
            if(len!=0)
                len=lps[len-1];
            else{
                lps[i]=0;
                i++;
            }
        }
    }
}
void kmp(string a,string b,int lps[],bool&ok)
{
    int i=0,j=0;
    int n=b.size(),m=a.size();
    while(i<n&&!ok)
    {
        if(b[i]==a[j])
        {
            i++;
            j++;
        }
        else if(i<n&&a[j]!=b[i])
        {
            if(j!=0)
                j=lps[j-1];
            else i++;
        }
        if(j==m)
        {
            ok=true;
        }
    }
}
void precompute_dinamica()
{
    for(int i=0;i<(1<<n);i++)
        for(int j=0;j<n;j++)
            dp[i][j][0]=INF,dp[i][j][1]=INF;
}
void dinamica_exponentiala(int sursa)
{
    precompute_dinamica();
    dp[1<<sursa][sursa][0]=0;
    dp[1<<sursa][sursa][1]=0;
    for(int bitmask=(1<<sursa)+1;bitmask<(1<<n);bitmask++)///parcurgem submultimile
      for(int i=0;i<n;i++)///parcurgem bitii din masca
        if(i!=sursa&&bitmask&(1<<i))///tratam cazul de drum minim de la sursa la sursa(nehamiltonian)
        {
            for (auto j: V[i])
                if (bitmask & (1 << j.first))///daca vecinul j pt care E j->i se afla in masca
                {if(dp[bitmask ^ (1 << i)][j.first][0] + j.second<dp[bitmask][i][0])
                    {dp[bitmask][i][0] =dp[bitmask ^ (1 << i)][j.first][0] + j.second;
                        parent[bitmask][i]=make_pair(make_pair(bitmask^(1<<i),j.first),0);}
                }
            for(auto j:V2[i])///arc special
                if(bitmask&(1<<j))
                {
                    int i2,j2,vmin=INF,checker=0;
                    if(dp[bitmask^(1<<i)][j][1]<dp[bitmask^(1<<i)][j][0])
                        vmin=dp[bitmask^(1<<i)][j][1];
                    else vmin=dp[bitmask^(1<<i)][j][0];
                    if(vmin<dp[bitmask][i][1])
                        dp[bitmask][i][1]=vmin,checker=1,parent[bitmask][i]=make_pair(make_pair(bitmask^(1<<i),j),checker);
                }
        }
}
int main()
{
    string s;
    f.open("adn.in",ios::in);
    g.open("adn.out",ios::out);
    f>>n;
    f.get();
    for(int i=0;i<n;i++)
    {
        f>>s;
        siruri.push_back(s);
    }
    string aux;
    int lps[2*smax];
    for(int i=0;i<n-1;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            ///calculam costul normal al arcului i->j
          aux.append(siruri[j]);
          aux.append("$");
          aux.append(siruri[i]);
          precompute(aux,lps);
          int cost=siruri[j].size()-lps[aux.size()-1];
          V[j].push_back(make_pair(i,cost));
          mat_ad[i][j]=cost;
          memset(lps,0,sizeof(lps));
          aux.clear();
          ///calculam costul normal al arcului j->i
          aux.append(siruri[i]);
          aux.append("$");
          aux.append(siruri[j]);
          precompute(aux,lps);
          int cost2=siruri[i].size()-lps[aux.size()-1];
          V[i].push_back(make_pair(j,cost2));
          mat_ad[j][i]=cost2;
          memset(lps,0,sizeof(lps));
          aux.clear();
          ///calculam costul special al arcului i->j(j se gaseste complet in i)
          if(siruri[j].size()<=siruri[i].size())///cautam pe siruri[j] in siruri[i]
          {
              precompute(siruri[j],lps);
              bool ok=false;
              kmp(siruri[j],siruri[i],lps,ok);
              if(ok==true)///se potriveste
                V2[j].push_back(i);
              memset(lps,0,sizeof(lps));
          }
            if(siruri[i].size()<=siruri[j].size())///cautam pe siruri[i] in siruri[j]
            {
                precompute(siruri[i],lps);
                bool ok=false;
                kmp(siruri[i],siruri[j],lps,ok);
                if(ok==true)///se potriveste
                    V2[i].push_back(j);
                memset(lps,0,sizeof(lps));
            }
        }
    }
    int dmin,smin,start;
    dmin=INF,smin=-1,start=-1;
    for(int k=0;k<n;k++) {
        dinamica_exponentiala(k);
        for (int i = 0; i < n; i++)
            if (i != k) {
                int dpmin=INF;
                if(dp[(1 << n) - 1][i][0]<dpmin)
                {
                    dpmin=dp[(1 << n) - 1][i][0];
                }
                if(dp[(1 << n) - 1][i][1]<dpmin)
                {
                    dpmin=dp[(1 << n) - 1][i][1];
                }
                if (dpmin + siruri[k].size() < dmin) {
                    dmin = dpmin + siruri[k].size();
                    smin = k;
                    start = i;
                }
            }
    }
    dinamica_exponentiala(smin);
    bool checker=0;
    if(dp[(1<<n)-1][start][0]+siruri[smin].size()==dmin)
        checker=0;
    else checker=1;
    int icurr=(1<<n)-1,jcurr=start,checkcurr=checker;
    stiva.push(jcurr);
    bool special[20];
    while(icurr)
    {
        if(parent[icurr][jcurr].second)
            special[parent[icurr][jcurr].first.second]=true;
        int iaux=icurr,jaux=jcurr;
        icurr=parent[iaux][jaux].first.first;
        jcurr=parent[iaux][jaux].first.second;
        stiva.push(jcurr);
    }
    stiva.pop();
    string sol;
    sol.append(siruri[stiva.top()]);
    int nodcurr=stiva.top();
    stiva.pop();
    if(!special[nodcurr])
        sol+=siruri[stiva.top()].substr(siruri[stiva.top()].size()-mat_ad[nodcurr][stiva.top()]);
    while(stiva.size()>1)
    {
        nodcurr=stiva.top();
        stiva.pop();
        if(!special[nodcurr])
            sol+=siruri[stiva.top()].substr(siruri[stiva.top()].size()-mat_ad[nodcurr][stiva.top()]);
    }
    g<<sol;
    f.close();
    g.close();
    return 0;
}