Tony's Log

Algorithms, Distributed System, Machine Learning

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

The default answer to LCS(consecutive or non-consecutive) is DP. Recurrence formula can be found at http://en.wikipedia.org/wiki/Longest_common_subsequence_problem . Calculation is O(mn) and printing is O(m+n). But this typical DP algorithm triggers TLE, as many others:

#include <vector>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
using namespace std;

/////////////////////////
#define gc getchar
int read_int()
{
  char c = gc();
  while(c<'0' || c>'9') c = gc();
  int ret = 0;
  while(c>='0' && c<='9') {
    ret = 10 * ret + c - 48;
    c = gc();
  }
  return ret;
}
int read_string(char *p)
{
    int cnt = 0;
    char c;
    while((c = gc()) == ' ');    //    skip spaces
    //
    while(c != 10)
    {
        p[cnt ++] = c;
        c = gc();
    }
    return cnt;
}
/////////////////////////
const int MaxLen = 1000;
int lcs[MaxLen][MaxLen];

struct Rec
{
    void init()
    {
        bMatch = false;
        c = '\0';
        offI = offJ = 0;
    }

    //    Match Info
    bool bMatch;
    char c;
    //    Offset
    int offI; int offJ;
};
Rec rec[MaxLen][MaxLen];

void clear()
{
    memset(lcs, 0, sizeof(int) * MaxLen * MaxLen);
    for(int i = 0; i < MaxLen; i ++)
    for(int j = 0; j < MaxLen; j ++)
    {
        rec[i][j].init();
    }
}

void print_path(int lstI, int lstJ)
{
    if(lstI < 0 || lstJ < 0) return;

    print_path(lstI + rec[lstI][lstJ].offI,
                lstJ + rec[lstI][lstJ].offJ);
    if(rec[lstI][lstJ].bMatch)
    {
        printf("%c %d %d\n", rec[lstI][lstJ].c, lstI + 1, lstJ + 1);
    }
}

void lcs_func(char *p1, int len1, char *p2, int len2)
{
    int maxLen = 0;
    int currI = 0; int currJ = 0;
    for(int i = 0; i < len1; i ++)
    for(int j = 0; j < len2; j ++)
    {
        if(p1[i] == p2[j])
        {
            int lst = (i == 0 || j == 0) ? 0 : lcs[i-1][j-1];
            lcs[i][j] = lst + 1;

            rec[i][j].offI = rec[i][j].offJ = -1;
            rec[i][j].bMatch = true;
            rec[i][j].c = p1[i];
        }
        else
        {
            int lst1 = (i == 0) ? 0 :lcs[i-1][j];
            int lst2 = (j == 0) ? 0 :lcs[i][j-1];
            int lg = max(lst1, lst2);
            lcs[i][j] = lg;

            if(lg == lst1)
            {
                rec[i][j].offI = -1;
            }
            else if(lg == lst2)
            {
                rec[i][j].offJ = -1;
            }
        }
        if(lcs[i][j] > maxLen)
        {
            maxLen = lcs[i][j];
            currI = i; currJ = j;
        }
    }

    if(maxLen > 1)
    {
        printf("Y\n");
        printf("%d\n", maxLen == 1 ? 0 : maxLen);
        print_path(currI, currJ);
    }
    else
    {
        printf("N\n");
    }
}
/////////////////////////
int main()
{
    int runcnt = read_int();
    for(int i = 1; i <= runcnt; i ++)
    {
        clear();

        int ccnt1 = read_int();
        char l1[1024];    read_string(l1);
        int ccnt2 = read_int();
        char l2[1024];    read_string(l2);

        printf("case %d ", i);
        lcs_func((char*)l1, ccnt1, (char*)l2, ccnt2);
    }

    return 0;
}
View Code - TLE

Well this problem does have a O(nlgn) algorithm: LCS->LIS. We need take special care of consecutive pattern like "aa", "aab"; and, we have to make sure only 1 index is chosen from each sub-seq, like 1, 3, 6, (4, 2) : the last 2 should not be taken into account.

#include <vector>
#include <cstdio>
#include <map>
#include <cstring>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

//////// Fast IO ////////
#define gc getchar
int read_int()
{
  char c = gc();
  while(c<'0' || c>'9') c = gc();
  int ret = 0;
  while(c>='0' && c<='9') {
    ret = 10 * ret + c - 48;
    c = gc();
  }
  return ret;
}
int read_string(char *p)
{
    int cnt = 0;
    char c;
    while((c = gc()) == ' ');    //    skip spaces
    //
    while(c != 10)
    {
        p[cnt ++] = c;
        c = gc();
    }
    return cnt;
}
void print_fast(char *p)
{
    fwrite(p, 1, strlen(p), stdout);
}
/////////////////////////
const int MaxLen = 1000;
struct cInfo
{
    cInfo(char rc, int ri1, int ri2)
    {
        set(rc, ri1, ri2);
    }
    void set(char rc, int ri1, int ri2)
    {
        c = rc; inx1 = ri1; inx2 = ri2;
    }

    char c;
    int inx1;
    int inx2;
};
struct comp_func
{
    bool operator() (const cInfo & left, const cInfo & right)
    {
        return left.inx2 < right.inx2;
    }
    bool operator() (const cInfo & left, const int & right)
    {
        return left.inx2 < right;
    }
    bool operator() (const int & left, const cInfo & right)
    {
        return left < right.inx2;
    }
};
/////////////////////////
void lcs_func_by_lis(char *p1, int len1, char *p2, int len2)
{
    //    Get shorter & longer string
    bool bS1Longer = len1 > len2;
    char *s = !bS1Longer ? p1 : p2;
    int lens = !bS1Longer ? len1 : len2;
    char *l = bS1Longer ? p1 : p2;
    int lenl = bS1Longer ? len1 : len2;

    //    Get indices array.
    vector<int> sInxSet[26];
    for(int j = 0; j < lenl; j ++)
    {
        sInxSet[l[j]-'a'].push_back(j);
    }

    //    LIS - Caveat: please make sure there's only one chosen in one seq(..)
    vector<cInfo> ret;
    for(int i = 0; i < lens; i ++)
    {
        int lstSpot = -1; // to make sure only 1 affects final seq
        char c = s[i];
        vector<int> &vec = sInxSet[c-'a'];
        for(int j = vec.size() - 1; j >= 0; j --)
        {
            vector<cInfo>::iterator iter =
                    upper_bound(ret.begin(), ret.end(), vec[j], comp_func());
            if(iter == ret.end())
            {
                ret.push_back(cInfo(c, i, vec[j]));
                lstSpot = ret.size() - 1;
            }
            else
            {
                int inx = iter - ret.begin();

                if(inx > 0)
                {
                    if(vec[j] == ret[inx - 1].inx2) break;
                }
                bool bOverw = inx == lstSpot;
                if(lstSpot == -1 ||  bOverw)
                {
                    ret[inx].set(c, i, vec[j]);
                    lstSpot = inx;
                }
            }
        }
    }

    if(ret.size() <= 1)
    {
        printf("N\n");
    }
    else
    {
        printf("Y\n");
        printf("%d\n", ret.size());
        for(unsigned i = 0; i < ret.size(); i ++)
        {
            printf("%c %d %d\n", ret[i].c,
                    bS1Longer ? ret[i].inx2 + 1 : ret[i].inx1 + 1,
                    bS1Longer ? ret[i].inx1 + 1 : ret[i].inx2 + 1);
        }
    }

}
/////////////////////////
int main()
{
    int runcnt = read_int();
    for(int i = 1; i <= runcnt; i ++)
    {
        int ccnt1 = read_int();
        char l1[1024];    read_string(l1);
        int ccnt2 = read_int();
        char l2[1024];    read_string(l2);

        printf("case %d ", i);
        lcs_func_by_lis((char*)l1, ccnt1, (char*)l2, ccnt2);
    }

    return 0;
}
View Code (WA)

 

posted on 2014-02-18 14:19  Tonix  阅读(289)  评论(0)    收藏  举报