hdu1827&&hdu2767----Kosaraju算法
2013-05-23 00:00
232 查看
/** * hdu1827 * 题意:给一个有向图,每个顶点有个权值,求入度为0的顶点的个数及从入度为0的顶点出发, * 到达图的所有顶点的最小花费和 * 解法:缩点后,从入度为0的顶点在反向图中dfs一遍,求出路径上的顶点的最小花费 **/ #include <cstdio> #include <cstring> #include <climits> #include <iostream> using namespace std; int scc[1005]; ///缩图,存强连通块 int dfn[1005]; ///存顶点访问顺序 int scc_root[1005]; ///存强连通分量中的某一个顶点 int ind[1005]; ///缩图,存入度数 bool vis[1005]; ///访问标记 int cost[1005]; ///花费 int sc, cnt, mincc; int minp, minc; ///sc 对同一个强连通子图中的顶点标记为同一标志 ///cnt ----- ///total 把每个强连通子图看成是一个点,统计其他点可到该点的数目 struct Node { int u; Node *next; Node() {} Node(int uu, Node *p=NULL) : u(uu), next(p){} }; struct Graph { Node *head; Graph() {} }G[1005], NG[1005]; void initG(int n) {///初始化 for (int i=1; i<=n; ++i) { G[i].head = NULL; NG[i].head = NULL; } } void buildG(Graph g[], int v, int u) {///建图 Node *p = new Node(u); p->next = g[v].head; g[v].head = p; } void dfs_one(int k) {///第一次dfs求顶点访问顺序 vis[k] = true; for (Node *p=G[k].head; p!=NULL; p=p->next) { if (!vis[p->u]) { dfs_one(p->u); } } dfn[++cnt] = k;///存顶点访问顺序 } void dfs_two(int k) {///第二次dfs缩图 scc[k] = sc; ///同一个强连通分量标记为一样的标志 vis[k] = true; for (Node *p=NG[k].head; p!=NULL; p=p->next) { if (!vis[p->u]) { dfs_two(p->u); } } } void dfs_three(int k) {///第三次dfs vis[k] = true; if (mincc > cost[k]) {///访问路径上的最小花费 mincc = cost[k]; } for (Node *p=NG[k].head; p!=NULL; p=p->next) { if (!vis[p->u]) { dfs_three(p->u); } } } void kosaraju(int n) { cnt = 0; memset(vis, false, sizeof(vis)); for (int i=1; i<=n; ++i) {///求顶点访问顺序 if (!vis[i]) { dfs_one(i); } } memset(vis, false, sizeof(vis)); sc = 0; for (int i=n; i>0; --i) {///缩图 if (!vis[dfn[i]]) { ++sc; scc_root[sc] = dfn[i]; dfs_two(dfn[i]); } } for (int i=1; i<=sc; ++i) { ind[i] = 0; } for (int i=1; i<=n; ++i) { for (Node *p=G[i].head; p!=NULL; p=p->next) { if (scc[i] != scc[p->u]) {///不在同一个强连通内 ++ind[scc[p->u]]; } } } minc = 0; minp = 0; for (int i=1; i<=sc; ++i) { if (ind[i] == 0) {///对入度为0的点进行第三次dfs ++minp; mincc = INT_MAX; memset(vis, false, sizeof(vis)); dfs_three(scc_root[i]); minc += mincc; /// minc += cost[scc_root[i]]; } } } void del(Node *pNode) { if (pNode != NULL) { del(pNode->next); delete pNode; pNode = NULL; } } void deleteG(Graph g[], int n) {///释放图 for (int i=1; i<=n; ++i) { if (g[i].head != NULL) { del(g[i].head); } } } int main(void) { int n, m; while (scanf("%d%d", &n, &m) != EOF) { initG(n); int v, u; for (int i=1; i<=n; ++i) { scanf("%d", &cost[i]); } while (m--) { scanf("%d%d", &v, &u); buildG(G, v, u); buildG(NG, u, v); } kosaraju(n); deleteG(G, n); deleteG(NG, n); printf("%d %d\n", minp, minc); } return 0; } /** * hdu2767 * 题意: 在一个有向图中,问至少加几条边让整个图变成强连通 * 解法:缩点后统计出度为0和入度为0的点的个数,两者取最大值 **/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int dfn[20005]; ///存顶点访问顺序 int scc[20005]; ///缩图,存强连通块 int ind[20005]; ///缩图,存入度数 int oud[20005]; ///缩图,存出度数 bool vis[20005]; ///访问标记 int cnt, sc; struct Node { int u; Node *next; Node() {} Node(int uu, Node *p=NULL) : u(uu), next(p){} }; struct Graph { Node *head; Graph() {} }G[20005], NG[20005]; void initG(int n) {///初始化 for (int i=1; i<=n; ++i) { G[i].head = NULL; NG[i].head = NULL; } } void buildG(Graph g[], int v, int u) {///建图 Node *p = new Node(u); p->next = g[v].head; g[v].head = p; } void dfs_one(int k) {///第一次dfs求顶点访问顺序 vis[k] = true; for (Node *p=G[k].head; p!=NULL; p=p->next) { if (!vis[p->u]) { dfs_one(p->u); } } dfn[++cnt] = k;///顶点访问顺序 } void dfs_two(int k) {///第二次dfs缩图 scc[k] = sc; ///同一个强连通分量标记为一样的标志 vis[k] = true; for (Node *p=NG[k].head; p!=NULL; p=p->next) { if (!vis[p->u]) { dfs_two(p->u); } } } int kosaraju(int n) { cnt = 0; memset(vis, false, sizeof(vis)); for (int i=1; i<=n; ++i) {///求顶点访问顺序 if (!vis[i]) { dfs_one(i); } } memset(vis, false, sizeof(vis)); sc = 0; for (int i=n; i>0; --i) {///缩图 if (!vis[dfn[i]]) { ++sc; dfs_two(dfn[i]); } } for (int i=1; i<=sc; ++i) { ind[i] = oud[i] = 0; } for (int i=1; i<=n; ++i) { for (Node *p=G[i].head; p!=NULL; p=p->next) { if (scc[i] != scc[p->u]) {///不在同一个强连通内 ++oud[scc[i]]; ++ind[scc[p->u]]; } } } int max1 = 0; int max2 = 0; for (int i=1; i<=sc; ++i) { if (ind[i] == 0) ++max1; if (oud[i] == 0) ++max2; } int ans = max(max1, max2); if (sc == 1) ans = 0; return ans; } void deleteG(Graph g[], int n) {///释放图 for (int i=1; i<=n; ++i) { Node *p = g[i].head; if (p != NULL) { Node *pt = p->next; while (p != NULL) { delete p; if (pt == NULL) { p = NULL; break; }else { p = pt; pt = pt->next; } } g[i].head = NULL; } } } int main(void) { int t, n, m; scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); initG(n); while (m--) { int u, v; scanf("%d%d", &v, &u); buildG(G, v, u); buildG(NG, u, v); } int ans = kosaraju(n); printf("%d\n", ans); deleteG(G, n); deleteG(NG, n); } return 0; }
相关文章推荐
- 强连通分量_Kosaraju算法
- 【Python排序搜索基本算法】之深度优先搜索、广度优先搜索、拓扑排序、强联通&Kosaraju算法
- Kosaraju算法---强联通分量
- kosaraju算法
- poj1236 Network of Schools--Kosaraju算法 & 缩点 & 强连通分量
- 强连通分量Kosaraju算法实现
- Kosaraju算法解决强连通问题
- 【Python排序搜索基本算法】之深度优先搜索、广度优先搜索、拓扑排序、强联通&Kosaraju算法
- Kosaraju算法---强联通分量
- 强连通分量-kosaraju算法
- poj2553 The Bottom of a Graph--Kosaraju算法 & 缩点 & 强连通分量
- 一句话之--tarjan算法、kosaraju算法,求强连通分量
- 强连通分量 Kosaraju算法
- 强连通分支及kosaraju算法
- 半连通分量--Tarjan/Kosaraju算法
- 强连通分量 Kosaraju算法
- 有向图—拓扑排序,Kosaraju算法
- Kosaraju算法详解
- 强连通Kosaraju算法--不知道哪里错了?请教高手~~
- Poj 1236 (scc- Kosaraju算法实现)