这道题给出了解决一类问题的思路。我们把一个人可能在的所有点看成一个集合,把一个集合看成一个点,考虑集合之间的转移关系,在这一张新图上考虑问题。官方题解上说了,只要考虑所有两个点够成的集合和一个点构成的集合就可以了。因为我们并不去关注一个集合里面有哪些点,而是去关注这个集合里是不是只有个点。而且一个大的集合必然可以由两个两个的集合拼起来构成,所以所有两两的集合和一个点的集合足以表征所有集合的性质。剩下的问题就迎刃而解了。
#include <bits/stdc++.h>
#define maxn 10009
using namespace std;
vector<int>G[maxn];
int low[maxn],dfn[maxn],stk[maxn],in[maxn],top,bcnt,id[109][109],dfs_time,d[maxn];
int n,N;
void tarjan(int u)
{
dfn[u]=low[u]=++dfs_time;
stk[++top]=u;
in[u]=1;
for(int i=0;i<(int)G[u].size();i++)
{
int v=G[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(in[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
bcnt++;
int x;
do
{
x=stk[top--];
in[x]=0;
}while(x!=u);
}
}
bool solve(int i,int j,vector<string> &a)
{
vector<int>tmp;
for(int k=0;k<N;k++)
{
if(a[i][k]=='Y'||a[j][k]=='Y')
{
tmp.push_back(k);
}
}
int sz=tmp.size();
if(sz==0)
return 1;
else if(sz==1)
{
G[id[i][j]].push_back(tmp[0]);
return 1;
}
else
{
for(int x=0;x<sz;x++)
for(int y=x+1;y<sz;y++)
{
if(id[i][j]==id[tmp[x]][tmp[y]])
return 0;
G[id[i][j]].push_back(id[tmp[x]][tmp[y]]);
}
return 1;
}
}
int dfs(int u)
{
if(d[u]!=-1)
return d[u];
d[u]=0;
for(int i=0;i<(int)G[u].size();i++)
{
d[u]=max(d[u],dfs(G[u][i])+1);
}
return d[u];
}
class ScotlandYard
{
public:int maxMoves(vector <string> A, vector <string> B, vector <string> C)
{
N=A.size();
n=N*(N-1)/2+N;
int cur=N;
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
id[i][j]=cur++;
}
}
for(int i=0;i<N;i++)
{
for(int j=i+1;j<N;j++)
{
if(solve(i,j,A)==0)
return -1;
if(solve(i,j,B)==0)
return -1;
if(solve(i,j,C)==0)
return -1;
}
}
for(int i=0;i<n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
if(bcnt!=n)
return -1;
memset(d,-1,sizeof(d));
int ans=-1;
for(int i=0;i<n;i++)
{
ans=max(ans,dfs(i));
}
return ans;
}
};