您的位置:首页 > 其它

poj1236强连通缩点

2013-08-01 15:06 381 查看
题意:给出每个学校的list 代表该学校能链接的其他学校,问1:至少给几个学校资源使所有学校都得到;2:至少加多少个边能让所有学校相互连通;

思路:1:找出缩点后入度为零的点个数 2:找出缩点后入度为零个数和出度为零个数之间的最大值。

这题主要是在思考出入度和连通间的关系,了解了这个关系后就很水了。同时要注意图一开始就连通的情况。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define MAXN 10100
#define MAXM 10100

struct Edge
{
int v, next;
}edge[MAXM];    //边结点数组

int first[MAXN], stack[MAXN], DFN[MAXN], Low[MAXN], Belong[MAXM];
int indegree[MAXN],outdegree[MAXN];
// first[]头结点数组,stack[]为栈,DFN[]为深搜次序数组,Belong[]为每个结点所对应的强连通分量标号数组
// Low[u]为u结点或者u的子树结点所能追溯到的最早栈中结点的次序号
int instack[10010];  // instack[]为是否在栈中的标记数组
int n, m, cnt, scnt, top, tot;

void init()
{
cnt = 0;
scnt = top = tot = 0;    //初始化连通分量标号,次序计数器,栈顶指针为0
memset(first, -1, sizeof(first));
memset(DFN, 0, sizeof(DFN));   //结点搜索的次序编号数组为0,同时可以当是否访问的数组使用
memset(indegree,0,sizeof(indegree));
memset(outdegree,0,sizeof(outdegree));
}

void read_graph(int u, int v) //构建邻接表
{
edge[tot].v = v;
edge[tot].next = first[u];
first[u] = tot++;
}

void Tarjan(int v)       //Tarjan算法求有向图的强连通分量
{
int min, t;
DFN[v] = Low[v] = ++tot;    //cnt为时间戳
instack[v] = 1;    //标记在栈中
stack[top++] = v;      //入栈
for(int e = first[v]; e != -1; e = edge[e].next)
{   //枚举v的每一条边
int j = edge[e].v;   //v所邻接的边
if(!DFN[j])
{   //未被访问
Tarjan(j);    //继续向下找
if(Low[v] > Low[j]) Low[v] = Low[j];  // 更新结点v所能到达的最小次数层
}
else if(instack[j] && DFN[j] < Low[v])
{   //如果j结点在栈内,
Low[v] = DFN[j];
}
}
if(DFN[v] == Low[v])
{     //如果节点v是强连通分量的根
scnt++;   //连通分量标号加1
do
{
t = stack[--top];   //退栈
instack[t] = 0;   //标记不在栈中
Belong[t] = scnt;   //出栈结点t属于cnt标号的强连通分量
}while(t != v);  //直到将v从栈中退出
}
}

void solve()
{
for(int i = 1; i <= n; i++)   //枚举每个结点,搜索连通分量
if(!DFN[i])  //未被访问
Tarjan(i);  //则找i结点的连通分量
}
int e1[MAXN];int e2[MAXN];
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
{
int v;
while(scanf("%d",&v),v!=0)
{
e1[tot]=i;
e2[tot]=v;
read_graph(i, v);
}
}
solve();     //求强连通分量
for(int i=0;i<tot;i++)
{
if(Belong[e1[i]]!=Belong[e2[i]])
{
indegree[Belong[e2[i]]]++;
outdegree[Belong[e1[i]]]++;
}
}
int in,out,ans;
in=0;out=0;ans=0;
for(int i=1;i<=scnt;i++)
{
if(indegree[i]==0)
in++;
if(outdegree[i]==0)
out++;
}
printf("%d\n",in);
if(scnt==1)
printf("0\n");
else
{
ans=max(in,out);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: