pku1795 DNA Laboratory 状压DP

做的快哭惹QAQQQQQQQQQ,周伟的论文不知是老师给的版本问题还是啥看不到题解!!!!!!QAQQQQQQ

然后我决定自行解决

我们可以想到用一个状态表示已经选择的字符串,然而发现这个不对劲,因为一个字符串是有顺序的!

然后机智的我发现拼接只和尾巴那个字符串有关!很好我们就可以多加一维来表示当前状态下的字符串最后一串之前是谁的

很好我们搞定了状态就几乎等同于搞定了这个状压DP的大部分惹(当时的我就是这么天真)

然后直接选取最终状态最小的答案,然而发现这个并不是要求最小长度,而是字典序的字符串!

哎然后我竟觉得这是一个带状态的字符串dfs,然后怒T,= =

好吧时间挂掉的不是一点点= =

然后回来思考,这东西不就是倒着搜出来嘛!

然后DFS!!!

可是我发现= =早知道……就……不写……那样的……状态了……那样子写倒着DFS会T的= =,(那如何写DP可以使DFS不T而且很快就留给乃们思考惹)

然后……祭出大招再逆着DP一次!不管爆不爆写一次先!

然后= =发现早知道我最开始的时候开的是string就好惹,要字符数组何用!

下面代码里的dfs是没有用的,然而我留下来是为了警醒世人2333333333其实是增加代码长度让这题看起来更难一些

最终还是调了几次A了= =算是做完了状压DP的入门题惹,高兴<( ̄ˇ ̄)/ 一天搞定了最后两题

Problem: 1795		User: BPM136
Memory: 23848K		Time: 1547MS
Language: G++		Result: Accepted
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<bitset>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define down(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,x) for(int i=last[x];i!=0;i=e[i].next)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 15
#define LEN 105
#define inf 1<<30
int f[1<<N+5][N+5];
bool ra[1<<N+5][N+5];
int cost[N+5][N+5];
struct String
{
	char s[LEN+5];
	int len;
	bool operator< (const String &a)const
	{
		return strcmp(s,a.s)<0;
	}
}s[N+5];
int n,m;
bitset<N+1>a;
bitset<N+1>v;
string ans;

int cal(int x,int y)
{
	int anss=0;
	fo(i,0,s[y].len-1)
	if(i+1<=s[x].len)
	{
		int flag=1,posx=s[x].len-1;
		down(j,i,0)
		if(s[x].s[posx--]!=s[y].s[j])flag=0;
		if(flag)anss=max(anss,i+1);
	}
	return s[y].len-anss;
}

void init()
{
	n=read();int cnt=0;
	fo(i,1,n)
	{
		scanf("%s",s[++cnt].s);
		fo(j,1,cnt-1)
		{
			if(strstr(s[j].s,s[cnt].s)!=NULL)
			{
				cnt--;
				break;
			}
			if(strstr(s[cnt].s,s[j].s)!=NULL)
			{
				strcpy(s[j].s,s[cnt].s);
				cnt--;
				break;
			}
		}
	}
	n=cnt;
	sort(s+1,s+n+1);
	fo(i,1,n)s[i].len=strlen(s[i].s);
	
//	fo(i,1,n)cout<<s[i].s<<' '<<s[i].len<<endl;

	fo(i,0,(1<<n)-1)
	fo(j,1,n)f[i][j]=inf;
	
	fo(i,1,n)
	fo(j,1,n)
	if(i!=j)cost[i][j]=cal(i,j);
	else cost[i][j]=0;
	
	fo(i,1,n)f[0][i]=0,f[1<<(i-1)][i]=s[i].len;
	
	memset(ra,0,sizeof(ra));
}

int lo[N+5];
void dfs(int k,int cur,int now)
{
	a=now;
//	cout<<k<<' '<<cur<<' '<<a<<' '<<v<<endl;
	v[cur]=1;
	lo[k]=cur;
	if(k==n)
	{
		string ss=s[cur].s;//cout<<lo[n]<<' ';
		down(i,n-1,1)
		{
//			cout<<lo[i]<<endl;
			fo(j,s[lo[i]].len-cost[lo[i+1]][lo[i]],s[lo[i]].len-1)
			{
				ss+=s[lo[i]].s[j];
			}
		}
		if(ss<ans||ans=="")ans=ss;
		return;
	}
	string ss;
//	cout<<f[now][cur]<<' '<<now<<' '<<cur<<endl;
//	cout<<f[now-(1<<1)][2]<<' '<<cost[2][cur]<<endl;
	fo(i,1,n)
	if(!v[i]&&f[now][cur]==f[now-(1<<(cur-1))][i]+cost[i][cur])
	{
		dfs(k+1,i,now-(1<<(cur-1)));
		lo[k+1]=0;v[i]=0;
	}
}

int main()
{
	int tttt=read(),tot=0;
	while(tttt--)
	{
		init();
		fo(i,1,(1<<n)-1)
		{
			a=i;int anum=a.count();
			fo(j,1,n)
			if(f[i][j]!=inf&&a[j-1])
			{
				fo(k,1,n)
				if(!a[k-1])
				{
					f[i|(1<<(k-1))][k]=min(f[i|(1<<(k-1))][k],f[i][j]+cost[j][k]);
//					cout<<f[i|(1<<(k-1))][k]<<' '<<f[i][j]<<' '<<cost[j][k]<<' '<<a<<' '<<j<<' '<<k<<endl;
				}
			}
		}
		
		int anss=inf,las=0;
		fo(i,1,n)
		if(anss>f[(1<<n)-1][i])
		{
			anss=f[(1<<n)-1][i];
			las=i;
		}
//		cout<<anss<<' '<<las<<endl;
		v.reset();ans="";
//		dfs(1,las,(1<<n)-1);

		fo(i,1,n)
		if(f[(1<<n)-1][i]==anss)
		{
			ra[(1<<n)-1][i]=1;
		}
		
		down(i,(1<<n)-1,0)
		{
			a=i;
			fo(j,1,n)
			if(ra[i][j])
			{
				fo(k,1,n)
				if(j!=k&&a[k-1])
				if(f[i-(1<<(j-1))][k]+cost[k][j]==f[i][j])
				{
					ra[i-(1<<(j-1))][k]=1;
				}
			}
		}
		
		string tt=string(1,'z'+1);int pos=0;
		fo(i,1,n)
		if(ra[1<<(i-1)][i]&&s[i].s<tt)
		{
			tt=s[i].s;
			pos=i;
		}
		
//		cout<<pos<<' '<<tt<<endl;
		int beg=1<<(pos-1);ans=tt;
		fo(ci,1,n-1)
		{
			a=beg;int v=-1;
			string ta=string(1,'z'+1);
			fo(i,1,n)
			{
				
				if(a[i-1]==0)
				if(ra[beg|(1<<(i-1))][i])
				if(f[beg|(1<<(i-1))][i]==f[beg][pos]+cost[pos][i])
				{
					string tt="";
					fo(k,s[i].len-cost[pos][i],s[i].len-1)tt+=s[i].s[k];
					if(tt<ta)
					{
						ta=tt;
						v=i;
					}
				}
			}
			pos=v;
			beg|=1<<(pos-1);
			ans+=ta;
		}
		printf("Scenario #%d:\n%s\n\n",++tot,ans.c_str());
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值