名人:所有人都认识名人,名人不认识其他任何人
//由题目可判断出,名人最多只有一个,反证:若存在两个名人,则不符合
法一:穷举 O(n^2)
法二:O(n) 空间:O(n)
思路:若A认识B,那么A一定不是名人
代码:
int findstar()
{
for(int i=0;i<n;i++)//n为人数
a[i]=i;
while(n>1){
if(known(a[0],a[1]))
a[0]=a[--n];
else
a[1]=a[--n];
}
for(int i=0;i<n;i++){
if(a[0]!=i&&(known(a[0],a[i])||!known(a[i],a[0])))
return -1;
}
return a[0];
}
法三:
空间优化 空间O(1) 一头扫
int findstar()
{
int star=0;
for(int i=1;i<n;i++)
if(known(star,i))
star=i;
return star;
}
法四:空间优化 空间O(1) 两头扫
int findstar()
{
int top=0,tail=n-1;
while(top>tail){
if(known(top,tail))
top++;
else if(known(tail,top))
tail--;
}
return top;
}
老师:
/* 名人问题:有n个人他们之间认识与否用邻接矩阵表示(1表示认识,0表示不认识),
并且A认识B并不意味着B认识A,名人定义为他不认识任何人,且所有人都认识他。请求出所有名人 */
分析:只有一个名人(反证法)
方案一:穷举 O(n^2)
方案二:o(n) 空间o(n))
for (int i=0;i<n;i++)
a[i]=i; //没检查过的人
while (n>1)) {
if (known[a[0],a[1]]) a[0]=a[--n]; //删除认识的人 a[i]=a[--n]
else a[1]=a[--n];
}
for (int i=0;i<n;i++)
if (a[0]) != i)&&(known[a[0]][i]||!known[i][a[0]]])
return -1;
return a[0];
方案三:空间优化 空间o(1) 一头扫
i<j [0...i-1]没有名人, [i...j-1] 没有名人
若i认识j,删除i :i=j,j=j+1
i不认识j,删除j:j=j+1
int i=0,j=1;
for (;j<n;++j) { if (known[i][j]) i =j; }
for (j=0;j<n;++j) {
if ((i!=j)&&(known[i][j]||!known[j][i])) return -1; //没有名人
}
return i;
方案四: 空间优化 空间o(1) 两头扫
i=0,j=n-1
i<j [0...i-1]没有名人, [j+1...n-1] 没有名人
若i认识j,删除i :++i
i不认识j,删除j:--j
int i=0,j=n-1;
while (i<j)
if known[i][j] ++i;
else --j;
for (j=0;j<n;++j) {
if ((i!=j)&&(known[i][j]||!known[j][i])) return -1; //没有名人
return i;