题意是:给出一个有向图 , 假设x点满足一个条件 , 即除本身外 , 其他所有点都能到达点x(不一定是相连 , 间接到达也行) ,
这个点x就是最受欢迎的点, 问这样的点有多少了 。
1、这题可以直接暴力求解 , 时间是够的 , 当要先做预处理 , 就是在输入边的时 , 把所有边都反向存储 。
然后再从每一个点出发去遍历 , 如果可以到达其他所有点那么这个点就是最受欢迎的点 。
2、先求出原图的所有强连通分量 , 然后再用强连通分量去构成一个新图 , 然后再用这个新图去像方法1那么遍历 。
解法2的优化:
1、在遍历新图时 , 上个被遍历的点 , 可以不做为出发点去遍历了 , 因为这个新图是一个DAG图 , 不存在环了。
2、对于这个新图 , 只有三中情况:1、所有点都是x点 , 2、只有一个点事x点 , 3、所有点都不是x点 。
其实解法2比1快很多 , 但是由于这题的数据太水了 , 所以完全没有体现出解法2的快速 。
解法2的代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 10010 ;
vectorgrap[MAXN] , scc[MAXN];
int pre[MAXN] , lowlink[MAXN] , sccno[MAXN];
int n , m , dfs_clock , scc_cnt , p[MAXN];
stacks;
void init()
{
for(int i =
1 ; i <= n; i++)
{
grap[i].clear();
scc[i].clear();
p[i] =
i;
}
}
int find(int x) // 并查集判断 ,
是不是连通图
{
int y =
x;
while(x !=
p[x])
x =
p[x];
while(y !=
x)
{
int gh =
p[y];
p[y] =
x;
y =
gh;
}
return
x;
}
int fun() // 判断是不是连通图
{
int x =
0;
for(int i =
1; i <= n; i++)
{
if(p[i] ==
i)
if(++x >
1) return 0;
}
return
1;
}
void dfs(int u) // 寻找强连通分量
{
lowlink[u] =
pre[u] = ++dfs_clock;
s.push(u);
for(int i =
0 ; i < grap[u].size() ; i++)
{
int v =
grap[u][i];
if(!pre[v])
{
dfs(v);
if(lowlink[u] > lowlink[v]) lowlink[u] =
lowlink[v];
}
else
if(!sccno[v] && lowlink[u] > pre[v])
lowlink[u] =
pre[v];
}
if(lowlink[u] == pre[u])
{
scc_cnt++;
for(;
;)
{
int x =
s.top() ; s.pop();
sccno[x] =
scc_cnt;
if(x ==
u) break;
}
}
}
void find_scc()
{
memset(pre,
0 , sizeof(pre));
memset(sccno
, 0 , sizeof(sccno));
dfs_clock =
scc_cnt = 0;
for(int i =
1; i <= n; i++)
{
if(!pre[i]) dfs(i);
}
}
void dfs2(int u) //遍历新图的点
{
//cout<<u<<endl;
p[u] =
pre[u] = 1;
for(int i =
0 ; i < scc[u].size() ; i++)
{
int v =
scc[u][i];
if(!p[v])
dfs2(v);
}
}
int max_cow() //
求出有多少最受欢迎的cow
{
int i , x =
0 , j;
memset(pre ,
0 , sizeof(pre));
for(i = 1; i
<= scc_cnt ; i++)
if(!pre[i])
{
memset(p , 0
, sizeof(p));
dfs2(i);
for(j = 1; j
<= scc_cnt; j++) // 只要找到一个点是
, 就可直接退出
if(p[j] ==
0) break;
if(j >
scc_cnt) {x = i ; break;}
}
if(!x) return x;
int maxcow =
0;
for(i = 1; i
<= n; i++)
if(sccno[i]
== x) maxcow += 1;
return
maxcow;
}
int main()
{
while(scanf("%d %d" , &n , &m) != EOF)
{
init();
int i , x ,
y , j;
for(i = 0 ;
i < m; i++)
{
scanf("%d
%d" , &x , &y);
grap[x].push_back(y);
int g =
find(x) , h = find(y);
if(g !=
h) p[h] = g;
}
int bz =
fun();
if(!bz) {printf("%d\n" , 0);
continue ;}
find_scc();
if(scc_cnt
== 1) { printf("%d\n" ,
n); continue ;} // 如果整个图都是强连通图
, 那么就所以cow都是最受欢迎的
for(i = 1; i
<= n; i++)
for(j = 0 ;
j < grap[i].size(); j++)
{
int v =
grap[i][j];
x = sccno[i]
;
y =
sccno[v];
if(x !=
y) scc[y].push_back(x);
}
x =
max_cow();
printf("%d\n" , x);
}
return
0;
}
1、这题可以直接暴力求解 , 时间是够的 , 当要先做预处理 , 就是在输入边的时 , 把所有边都反向存储 。
然后再从每一个点出发去遍历 , 如果可以到达其他所有点那么这个点就是最受欢迎的点 。
2、先求出原图的所有强连通分量 , 然后再用强连通分量去构成一个新图 , 然后再用这个新图去像方法1那么遍历 。
解法2的优化:
1、在遍历新图时 , 上个被遍历的点 , 可以不做为出发点去遍历了 , 因为这个新图是一个DAG图 , 不存在环了。
2、对于这个新图 , 只有三中情况:1、所有点都是x点 , 2、只有一个点事x点 , 3、所有点都不是x点 。
其实解法2比1快很多 , 但是由于这题的数据太水了 , 所以完全没有体现出解法2的快速 。
解法2的代码:
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 10010 ;
vectorgrap[MAXN] , scc[MAXN];
int pre[MAXN] , lowlink[MAXN] , sccno[MAXN];
int n , m , dfs_clock , scc_cnt , p[MAXN];
stacks;
void init()
{
}
int find(int x)
{
}
int fun()
{
}
void dfs(int u)
{
}
void find_scc()
{
}
void dfs2(int u)
{
}
int max_cow()
{
}
int main()
{
}