基因

Problem Description

作为一个基因工程师,Enigma遇到了一个关于基因重组的难题。总所周知,基因可以被看出一个核苷酸序列,这个序列可以简单地用四个字母A,C,G和T表示。
Enigma得到了一个基因“ATCC”,他想把它重组为一个新的基因“CTCA”。他可以任意使用下列两种方法:(1) 交换基因的前两个字符; (2) 将第一个字符移到最后。例如:“ATCC”经过方法2重组为“TCCA”,然后“TCCA”经过方法1重组从而得到了“CTCA”。你的任务是写个程序帮助Enigma发现重组基因的最小步骤。

Input

输入有多个实例,每个实例的第1行整数N表示基因的长度(1<=N<=12)。第2行为需要重组的基因,第3行为重组后的基因。输入为0表示结束。

Output

对于每个实例输出最小的步骤数。

Sample Input

4
ATCC
CTCA
4
ATCG
GCTA
4
ATCG
TAGC
0

Sample Output

2
4
6

关键是hash函数的构建

#include<iostream>
#include<queue>
#include<string>
#define mai 4
#define maxin 369600
using namespace std;
bool visit[369600];
int total,n;
int c[4];
int a[12];
int b[12];
int ss[12];
int temp1,temp2;
int p[8];
void tanslate(int x,int p[])
{
 int i;
 for(i=n-1;i>=0;i--)
 {
  p[i]=x%4;
  x/=4;
 }
}
int fan(char s)
{
 if(s=='A')  return 0;
 else if(s=='T') return 1;
 else if(s=='C')  return 2;
 else if(s=='G') return 3;
}
int lmx(int c[])
{
 int i,sum=0;
 for(i=0;i<n;i++)
 {
  sum=sum*mai+c[i];
 }
 return sum;
}
int ff[4];
int pp[4];
int hash(int *s)
{
 int ret=0,sum=total,i,j;
 for(i=0;i<4;i++)
 {
  pp[i]=ff[i];
 }
 for(i=0;i<n;i++)
 {
  for(j=0;j<s[i];j++)
  {
   if(pp[j]) ret+=sum*pp[j]/(n-i);
  }
  sum=sum*pp[s[i]]/(n-i);
  pp[s[i]]--;
 }
 return ret;
}
void swap(int &x,int &y)
{
 int temp=x;
 x=y;
 y=temp;
}

struct lmxi{
 int x;
 int step;
};
queue<lmxi>q;
int bfs()
{
 int i;
 lmxi s1,s2,s3;
 while(!q.empty()) q.pop();
 s1.x=temp1;
 s1.step=0;
 if(temp1==temp2)  return 0;
 tanslate(s1.x,a);
 visit[hash(a)]=true;
 q.push(s1);
   while(!q.empty())
 {
        s2=q.front();
  q.pop();
  if(s2.x==temp2)  return s2.step;
  for(i=0;i<2;i++)
  {
   tanslate(s2.x,a);
   if(i==0)
   {
    swap(a[0],a[1]);
   }
   else
   {
    int j,ts;
    ts=a[0];
    for(j=0;j<n-1;j++)
    {
     a[j]=a[j+1];
    }
    a[n-1]=ts;
   }
   int sm=hash(a);
   if(visit[sm]!=true)
   {
     int t=lmx(a);
    if(t==temp2)  return s2.step+1;
    else {
        visit[sm]=true;s3.step=s2.step+1;s3.x=t;q.push(s3);
    }
   }
  }
 }
}
int main()
{
  int ca,i;
  string s1,s2;
  while(cin>>ca)
  {
   if(ca==0) break;
   cin>>s1>>s2;
   n=s1.length();
   for(i=0;i<s1.length();i++)
   {
    a[i]=fan(s1[i]);
   }
   for(i=0;i<s2.length();i++)
   {
    b[i]=fan(s2[i]);
   }
   memset(visit,0,sizeof(visit));
   temp1=lmx(a);
   temp2=lmx(b);
   total=1;
   memset(c,0,sizeof(c));
   memset(ff,0,sizeof(ff));
   for(i=0;i<n;i++)
   {
    c[a[i]]++;
    ff[a[i]]++;
    total*=(i+1);
   }
   for(i=0;i<4;i++)
   {
    if(c[i]==0)  continue;
    else
    {
     while(c[i])
     {
      total/=c[i];
      c[i]--;
     }
    }
   }
   cout<<bfs()<<endl;
  }
  return 0;
}

转载于:https://www.cnblogs.com/ffhuguang/archive/2013/03/17/2965028.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值