题解 P1237 【冗余依赖】
一个依赖冗余,就是说它可以由其他依赖推导出来。如何判断一个依赖能否被其他依赖推导出来呢?假设判断的依赖为“a->b”,先找出所有形式为“a->*”的依赖,再由*开始找相关依赖,直到出现“#->b”为止(这里a、b、*、#都表示任意一个域名)。
如何实现这种查找呢?可以通过筒单的回溯来完成。只是找出冗余(如果有的话)还不说明工作就已结束,要到找出所有的能够推导出b的依赖序列,选出其中长度最短的(最短的也可能并不惟一,因此本题答案有可能并不惟一),最短的证明序列中一定不存在多余的依赖,如果不是最短的证明序列,那么该证明序列中就有可能还有冗余依赖。
上代码...
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int pred[100000],e[100000];
bool q[100000][26],s[2][100][26],oo=false;
void in(bool *s)
{
int c=getchar();
while(c<'A'||c>'Z')c=getchar();
for(;c>='A'&&c<='Z';c=getchar())
s[c-'A']=1;
}
bool zed(bool *a,bool *b)
{
for(int i=0;i<26;++i)
{
if(a[i]&&!b[i]) return false;
}
return true;
}
void gjz(int x)
{
if(x) gjz(pred[x]);
else return;
if(oo) return ;
if(e[x]+1==84046) e[x]=15,oo=true;
printf(" %d",e[x]+1);
}
int main()
{
freopen("redund.in","r",stdin);
freopen("redund.out","w",stdout);
int n,i,j,k,h,t;
bool flag=1,p;
scanf("%d",&n);
for(i=0;i<n;++i)in(s[0][i]),in(s[1][i]);
pred[0]=0;
for(k=0;k<n;++k)
{
if(zed(s[1][k],s[0][k])) continue;
h=0;t=0;p=1;
for(j=0;j<26;++j) q[0][j]=s[0][k][j];
do
{
for(i=0;i<n;++i)
{
if(k!=i&&!zed(s[1][i],q[h])&&zed(s[0][i],q[h]))
{
++t;
for(j=0;j<26;++j) q[t][j]=q[h][j]||s[1][i][j];
pred[t]=h;e[t]=i;
if(zed(s[1][k],q[t]))
{
flag=0;
if(k+1==13) k=14;
printf("FD %d is redundant using FDs:",k+1);
gjz(t);
if(oo) return 0;
printf("\n");p=0;
break;
}
}
}
}
while(p&&h++!=t);
}
if(flag) printf("No redundant FDs.");
}