poj1236(*强连通分量,缩点)

来源:互联网 发布:时时彩巴丁算法 编辑:程序博客网 时间:2024/05/21 17:05
/*translation:n个学校组成一个网络,给出链接情况(单向图)。求要使得报文能够发往全部学校,最少需要发送多少个报文。要使得从任何一个学校能够到达任何一个学校,最少需要添加几条边?solution:强联通分量,缩点缩点后整张图就成了DAG,那么显然地第一个问题就是DAG上入度为0的点。主要在于第二个问题。如何添边才能得到最优解呢?方法如下:首先缩点后,可以得到一个DAG,然后求出DAG中所有的子树(入度0的点和该点出发可达的所有出度为0的点就构成了一个子树)。从子树的叶节点开始往其他子树的根节点连上边,这样得到的就是最优解了。可以看出第二个问题答案就是max(out, in)。其中out,in分别为出度入度0的节点个数。note:当强联通分量只有一个时需要特殊处理。*/#include <iostream>#include <cstdio>#include <vector>#include <cstring>using namespace std;const int maxn = 100 +5;int V;vector<int> G[maxn];vector<int> rG[maxn];vector<int> vs;bool used[maxn];int cmp[maxn], out[maxn], in[maxn];struct Edge{int from, to;Edge(int f, int t):from(f),to(t){}Edge() {}};vector<Edge> edges;void add_edge(int from, int to){edges.push_back(Edge(from, to));G[from].push_back(to);rG[to].push_back(from);}void dfs(int v){used[v] = true;for(int i = 0; i < G[v].size(); i++) {if(!used[G[v][i]])dfs(G[v][i]);}vs.push_back(v);}void rdfs(int v, int k){used[v] = true;cmp[v] = k;for(int i = 0; i < rG[v].size(); i++) {if(!used[rG[v][i]])rdfs(rG[v][i], k);}}int scc(){memset(used, 0, sizeof(used));vs.clear();for(int v = 0; v < V; v++) {if(!used[v])dfs(v);}memset(used, 0, sizeof(used));int k = 0;for(int i = vs.size() - 1; i >= 0; i--) {if(!used[vs[i]])rdfs(vs[i], k++);}return k;}int main(){//freopen("in.txt", "r", stdin);    while(~scanf("%d", &V)) {for(int i = 0; i < maxn; i++) {G[i].clear();rG[i].clear();}edges.clear();memset(in, 0, sizeof(in));memset(out, 0, sizeof(out));memset(cmp, 0, sizeof(cmp));int id;for(int i = 0; i < V; i++) {for(;;) {scanf("%d", &id);if(id == 0)break;add_edge(i, id - 1);}}int k = scc(); //求出强联通分量的个数if(k == 1) {printf("1\n0\n");continue;}for(int i = 0; i < edges.size(); i++) {int s = edges[i].from, t = edges[i].to;if(cmp[s] != cmp[t]) {out[cmp[s]]++;in[cmp[t]]++;}}int ans0 = 0;for(int i = 0; i < k; i++)if(!in[i])ans0++;printf("%d\n", ans0);int ans1 = 0;for(int i = 0; i < k; i++)if(!out[i])ans1++;ans1 = max(ans1, ans0);printf("%d\n", ans1);    }    return 0;}

0 0
原创粉丝点击