Brief Description:
给定一个n*n的矩阵A,A[i][j]=1表示i喜欢j,A[i][j]=0表示i不喜欢j。规定A[i][i]=0且对任意i,j(i!=j)有A[i][j]=1或A[j][i]=1,且A[i][j]!=A[j][i],表示任意2个人一定存在喜欢关系,但是不能互相喜欢,即在有向图,保证任意两点间仅有一条有向边。现在若发现有i喜欢j,j喜欢k,k喜欢i(三角恋关系)则输出"Yes",否则输出"No"。
Analysis:
比赛时这题队友暴力过的,但是对于n=2000,O(n^2)的算法比较妥当。
下面介绍O(n^2)的解法:
首先从i从0到n-1依次枚举,当前枚举到i时,可以将之前的0到i-1划分为2个部分left和right,i喜欢left中的每一个人,right中的每一个人喜欢i,现在的关键是能否找到left中的k喜欢right中的某一个人p,这样就找到了i->k->p->i,满足条件。
我们可以统计left中点的入度和lin(把left中每个点的入度加起来),出度和lout,left中节点个数l,right中节点个数r,
若lin-lout=r*l,则此时不存在三角恋,否则存在三角恋。
具体看以下代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 2005;
char a[maxn][maxn];
bool vis[maxn];
int n;
int main()
{
int cas,ta=1;
scanf("%d",&cas);
while(cas--){
int i,j,lin,lout,l,r;
scanf("%d",&n);
for(i=0; i<n; i++) scanf(" %s",a[i]);
int in[maxn]={0},out[maxn]={0};
for(i=0; i<n; i++){
if(i < 2){
if(i == 1){
if(a[0][1] == '1') in[1]=1,out[0]=1;
else in[0]=1,out[1]=1;
}
continue;
}
l = lin = lout = 0;
for(j=0; j<i; j++) // 2012_9_13评注:i是三角恋中序号最大的
if(a[i][j] == '1'){
l++; // left多1
lin += in[j]; lout += out[j]; out[i]++; in[j]++;
}else{
out[j]++; in[i]++;
}
r = i - l;
if(lin-lout != r*l) break;
}
printf("Case #%d: ",ta++);
if(i < n) puts("Yes");
else puts("No");
}
return 0;
}