图论一直以来都很弱,又不懂什么最小点基(实现方法)……AC的时候……真爽啊。。。。。
Victoria的舞会3 Victoria的舞会 系列 | ||
|
hoho~
先把题贴一下:
描述 Description | |||
Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。 Victoria准备邀请n个已经确定的人,可是问题来了: 这n个人每一个人都有一个小花名册,名册里面写着他能够通知到的人的名字。比如说在A的人名单里写了B,那么表示A能够通知到B;但是B的名单里不见的有A,也就是说B不见得通知到A。 Victoria觉得需要确定自己需要通知多少个人m,能够实际将所有人n都通知到。并求出一种方案以确定m的最小值是多少。 注意:自己的名单里面不会有自己的名字。Victoria可以自身通知到所有n个人。 | |||
输入格式 Input Format | |||
第一行一个数n。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1<=n<=200。 | |||
输出格式 Output Format | |||
一个数,m。 | |||
样例输入 Sample Input | |||
18 | |||
样例输出 Sample Output | |||
14 | |||
时间限制 Time Limitation | |||
各个测试点1s |
貌似有一个类似模拟的办法,VIJOS上有人说过了。
以下是我苦思冥想出来的成果,没想到一遍就AC了。
1 把原有向图G中强连通分量缩为一点
1.1 DFS(G),记录节点访问完成的顺序,也可以说是一次拓扑排序。
1.2 反转图每一条弧得到新图Gt。
1.3 按照1.1记录的顺序DFS(Gt),得到的森林里每一棵树都是一个强连通分量。(用并查集合并每一个访问到的节点,从而实现“缩”强连通分量)。得到一强连通分量为单位的图Gscc。
2 DFS(Gscc),再一次拓扑排序,记录强连通分量访问完成的顺序。
4 按照2记录的顺序DFS(Gscc),用并查集得到访问产生的森林。
5 统计最后森林中树的个数即可得到答案。
程序(K&R风格代码)有120+行的样子。。。
#include
<
stdio.h
>
#include < stdbool.h >
void toposort( void );
void topovisit( int i);
void reverse( void );
void contract( void );
void convisit( int i);
void contract2( void );
void convisit2( int i);
int rank[ 201 ], set [ 201 ];
void Makeset( int x)
... {
set[x]=x;
rank[x]=0;
}
int Find( int x)
... {
if(set[x]!=x)
set[x]=Find(set[x]);
return set[x];
}
void Link( int x, int y)
... {
if(rank[x]>rank[y])
set[y]=x;
else...{
set[x]=y;
if(rank[x]==rank[y]) rank[y]++;
}
}
void Union( int x, int y)
... {
Link(Find(x),Find(y));
}
int n,topo[ 201 ],p;
int nc;
bool gt[ 201 ][ 201 ],g[ 201 ][ 201 ],vis[ 201 ];
int main( void )
... {
int i,j,k;
int t,count=0;
FILE *fin=stdin;
fscanf(fin,"%d ",&n);
nc=n;
for(i=0;i<n;i++)...{
while(1)...{
fscanf(fin,"%d", &t);
if(!t) break;
g[i][t-1]=true;
}
Makeset(i);
}
toposort();
reverse();
contract();
toposort();
contract2();
for(i=0;i<n;i++) if(set[i]==i) count++;
printf("%d ",count);
return 0;
}
void toposort( void )
... {
int i;
memset(vis,0,sizeof(vis));
p=0;
for(i=0;i<n;i++) if(!vis[i]) topovisit(i);
}
void topovisit( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(g[i][j] && Find(i)!=Find(j) && !vis[j])...{
topovisit(j);
}
}
topo[p++]=Find(i);
}
void reverse( void )
... {
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(g[i][j]) gt[j][i]=true;
}
void contract( void )
... {
int j;
memset(vis,0,sizeof(vis));
for(j=0;j<n;j++) if (!vis[topo[j]]) convisit(topo[j]);
}
void convisit( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(gt[i][j] && !vis[j])...{
Union(i,j);
convisit(j);
}
}
}
void contract2( void )
... {
int j;
memset(vis,0,sizeof(vis));
for(j=0;j<p;j++) if (!vis[topo[j]]) convisit(topo[j]);
}
void convisit2( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(g[i][j] && !vis[j])...{
Union(i,j);
convisit(j);
}
}
}
#include < stdbool.h >
void toposort( void );
void topovisit( int i);
void reverse( void );
void contract( void );
void convisit( int i);
void contract2( void );
void convisit2( int i);
int rank[ 201 ], set [ 201 ];
void Makeset( int x)
... {
set[x]=x;
rank[x]=0;
}
int Find( int x)
... {
if(set[x]!=x)
set[x]=Find(set[x]);
return set[x];
}
void Link( int x, int y)
... {
if(rank[x]>rank[y])
set[y]=x;
else...{
set[x]=y;
if(rank[x]==rank[y]) rank[y]++;
}
}
void Union( int x, int y)
... {
Link(Find(x),Find(y));
}
int n,topo[ 201 ],p;
int nc;
bool gt[ 201 ][ 201 ],g[ 201 ][ 201 ],vis[ 201 ];
int main( void )
... {
int i,j,k;
int t,count=0;
FILE *fin=stdin;
fscanf(fin,"%d ",&n);
nc=n;
for(i=0;i<n;i++)...{
while(1)...{
fscanf(fin,"%d", &t);
if(!t) break;
g[i][t-1]=true;
}
Makeset(i);
}
toposort();
reverse();
contract();
toposort();
contract2();
for(i=0;i<n;i++) if(set[i]==i) count++;
printf("%d ",count);
return 0;
}
void toposort( void )
... {
int i;
memset(vis,0,sizeof(vis));
p=0;
for(i=0;i<n;i++) if(!vis[i]) topovisit(i);
}
void topovisit( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(g[i][j] && Find(i)!=Find(j) && !vis[j])...{
topovisit(j);
}
}
topo[p++]=Find(i);
}
void reverse( void )
... {
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(g[i][j]) gt[j][i]=true;
}
void contract( void )
... {
int j;
memset(vis,0,sizeof(vis));
for(j=0;j<n;j++) if (!vis[topo[j]]) convisit(topo[j]);
}
void convisit( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(gt[i][j] && !vis[j])...{
Union(i,j);
convisit(j);
}
}
}
void contract2( void )
... {
int j;
memset(vis,0,sizeof(vis));
for(j=0;j<p;j++) if (!vis[topo[j]]) convisit(topo[j]);
}
void convisit2( int i)
... {
int j;
vis[i]=true;
for(j=0;j<n;j++)...{
if(g[i][j] && !vis[j])...{
Union(i,j);
convisit(j);
}
}
}