POJ 1236 Network of Schools

来源:互联网 发布:西门子运动控制软件 编辑:程序博客网 时间:2024/05/24 02:44

大意不再赘述。

思路:

第1问:求一个有向图的最小点基。

第2问:求连接最小的边使得有向图变成一个强连通图。

最小点基怎么求?首先要去找最高强连通分量,即入度为0的强连通分量。最小点基就是从最高强连通分量中任选一个顶点,组成的顶点集B就是图G的一个最小点基。

连接最小的边使得有向图变为一个强连通图,即找入度为0与出度为0的最大值即可。

什么是最小权点基呢?设图G的每个顶点Vi都有一个非负的权值ai,使得顶点对应的权值ai之和最小的点基称为最小权点基。求最小权点基的算法是从最高强连通分量里取权值最小的顶点,组成最小权点基。

总结一下:最小点基是从最高强连通分量里任选一个顶点,组成最小点基。而最小权点基,是从最高强连通分量里取权值最小的顶点,组成最小权点基。

具体的题目有:POJ 1236(最小点基)、POJ 3592(最小权点基)

#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <string>using namespace std;const int MAXN = 1010;const int MAXM = 10010;const int INF = 0x3f3f3f3f;struct Edge{int v, next;}edge[MAXM];int n, m;int cnt;int scnt, top, tot;int first[MAXN], dfn[MAXN], low[MAXN], ins[MAXN], stack[MAXN];int belong[MAXN];int ind[MAXN], outd[MAXN];void init(){cnt = 0;scnt = tot = top = 0;memset(first, -1, sizeof(first));memset(ind, 0, sizeof(ind));memset(outd, 0, sizeof(outd));memset(ins, 0, sizeof(ins));}void read_graph(int u, int v){edge[cnt].v = v;edge[cnt].next = first[u], first[u] = cnt++;}void dfs(int u){int v;low[u] = dfn[u] = ++tot;ins[u] = 1;stack[top++] = u;for(int e = first[u]; e != -1; e = edge[e].next){v = edge[e].v;if(!dfn[v]){dfs(v);low[u] = min(low[u], low[v]);}else if(ins[v]){low[u] = min(low[u], dfn[v]);}}if(low[u] == dfn[u]){scnt++;do{v = stack[--top];belong[v] = scnt;ins[v] = 0;}while(u != v);}}void Tarjan(){for(int i = 1; i <= n; i++) if(!dfn[i])dfs(i);}void read_case(){init();for(int u = 1; u <= n; u++){int v;while(scanf("%d", &v) && v){read_graph(u, v);}}}void solve(){read_case();Tarjan();for(int u = 1; u <= n; u++){for(int e = first[u]; e != -1; e = edge[e].next){int v = edge[e].v;if(belong[u] != belong[v]){outd[belong[u]]++;ind[belong[v]]++;}}}int ans1 = 0, ans2 = 0;for(int i = 1; i <= scnt; i++){if(!ind[i]) ans1++;if(!outd[i]) ans2++;}printf("%d\n", ans1);printf(scnt == 1? "0\n":"%d\n", max(ans1, ans2));}int main(){while(~scanf("%d", &n)){solve();}return 0;}

原创粉丝点击