fzu2158

http://acm.fzu.edu.cn/problem.php?pid=2158

在密室逃脱游戏中,大家被困在一个密室中,为了逃出密室,需要找到正确的数字密码,于是大家分头行动,分别找到了密码的子序列,而后大家将得到的线索集中整理分析,大家想知道密码最少是多少位。第一行输入一个整数T,表示数据组数。接下来T组数据,对于每组数据,第一行输入一个整数n (1<=n<=7),表示有n个人,接下来第2到n+1行每行输入一串数字,分别表示第i个人得到的密码子序列(长度<=6)。

1
3
123
14
21
5
比赛的时候是3秒,以前在做搜索的遇到过类似的题目,我是用A*过的.....在这里被卡住了
fzu2158
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int len[8],n,flag,p,dp[8][10];
char s[8][8]; int deal()
{
int maxn=0;
for(int i=0;i<n;i++)
maxn=max(maxn,len[i]);
return maxn;
}
int deal1()
{
int sum=0;
for(int j=0;j<=9;j++)
{
int maxn=0;
for(int i=0;i<n;i++)
{
maxn=max(maxn,dp[i][j]);
}
sum+=maxn;
}
return sum;
}
void dfs(int step)
{
if(flag==1)
return;
int x=deal();
int y=deal1();
if(x==0)
{
flag=1;
return;
}
if(step+x>p||step+y>p)
return;
for(int i=0;i<n;i++)
{
if(len[i]==0) continue;
int f[10],cnt=0;
int tmp=len[i]-1;
int xx=s[i][tmp]-'0';
for(int j=0;j<n;j++)
{
if(len[j]==0) continue;
int tmp1=len[j]-1;
if(s[i][tmp]==s[j][tmp1])
{
len[j]--;
f[cnt++]=j;
dp[j][xx]--;
}
}
if(cnt)
{
dfs(step+1);
for(int i=0;i<cnt;i++)
{
int tmp2=f[i];
len[tmp2]++;
dp[tmp2][xx]++;
}
}
}
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
scanf("%d",&n);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
len[i]=strlen(s[i]);
for(int j=0;j<len[i];j++)
{
int tmp=s[i][j]-'0';
dp[i][tmp]++;
}
}
p=flag=0;
p=max(deal1(),deal());
while(1)
{
dfs(0);
if(flag==1)
break;
p++;
}
printf("%d\n",p);
}
return 0;
}

  比赛完了,挂出来是1s的时候,在朋友的提醒下,用dp过的,简单的说下思路:

我开了7维dp,每一维分别对应这一维的字符串还有多少个字母没有匹配完的情况下所需要的最少字符个数。

我采取的是从n个字符串的最后开始往前面匹配的,每次找一个字符,看它是否与其它几个字符串相应位置上的字符相等,相等就-1,我所采取的方法是记忆化搜索,感觉这样容易把思路提现出来.......下面是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define inf (1<<28)
int dp[7][7][7][7][7][7][7],n,t[8];
char s[8][10]; int dfs(int a,int b,int c,int d,int e,int f,int g)
{
if(a==0&&b==0&&c==0&&d==0&&e==0&&f==0&&g==0)
return 0;
if(dp[a][b][c][d][e][f][g]) return dp[a][b][c][d][e][f][g];
//int h[7];
/*h[0]=a;
h[1]=b;
h[2]=c;
h[3]=d;
h[4]=e;
h[5]=f;*/
int minx=inf;
//if(a>0)
for(int j=0;j<n;j++)
{
if(t[j]==0) continue;
int f[7],cnt=0;
int tmp=t[j];
for(int i=0;i<n;i++)
{
if(t[i]==0) continue;
int tmp1=t[i];
if(s[i][tmp1-1]==s[j][tmp-1])
{
//if(a==3&&b==2&&c==2)
//printf("%c %c %d %d\n",s[i][t[i]-1],s[j][t[j]-1],i,j);
f[cnt++]=i;
t[i]--;
}
}
//if(a==3&&b==2&&c==2)
//printf("%d %d %d\n",t[0],t[1],t[2]);
//if(t[0]==3&&t[1]==1&&t[2]==1)
//printf("%c\n",s[j][t[j]-1]);
if(cnt)
{
int p=1+dfs(t[0],t[1],t[2],t[3],t[4],t[5],t[6]);
minx=min(minx,p);
//if(a==2&&b==1&&c==2)
//printf("%d %d %d %d %d\n",t[0],t[1],t[2],minx,p-1);
for(int i=0;i<cnt;i++)
{
int x=f[i];
t[x]++;
}
}
}
dp[a][b][c][d][e][f][g]=minx;
//printf("%d %d %d %d\n",a,b,c,minx);
return minx;
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
scanf("%d",&n);
memset(dp,0,sizeof(dp));
memset(t,0,sizeof(t));
for(int i=0;i<n;i++)
{
scanf("%s",s[i]);
t[i]=strlen(s[i]);
//printf("%d\n",t[i]);
}
printf("%d\n",dfs(t[0],t[1],t[2],t[3],t[4],t[5],t[6]));
//for(int i=0;i<n;i++)
//printf("%d\t",t[i]);
}
return 0;
}

  

 
上一篇:Java多线程同步集合--并发库高级应用


下一篇:C# 多线程(lock,Monitor,Mutex,同步事件和等待句柄)