您的位置:首页 > 其它

hdu3072&&hdu3639----Kosaraju算法

2013-05-23 00:00 288 查看
/**
*  hdu3072
*  题意:给出有向图,每条边有权值,求出强连通分量之间的最小边权,最后边权相加
*  解析:缩图,更新不在同一个强连通分量的最小边权
**/
#include <cstdio>
#include <climits>
#include <cstring>
#include <iostream>

using namespace std;

int scc[50005];  ///缩图,存强连通块
int dfn[50005];  ///存顶点访问顺序
bool vis[50005]; ///访问标记
int ees[50005];
int sc, cnt;
///sc    对同一个强连通子图中的顶点标记为同一标志
///cnt   -----
struct Node {
int u;
int w;
Node *next;
Node() {}
Node(int uu, int ww, Node *p=NULL) : u(uu), w(ww), next(p){}
};
struct Graph {
Node *head;
Graph() {}
}G[50005], NG[50005];
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, int w) {///建图
Node *p = new Node(u, w);
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)  {
ees[i] = INT_MAX;
}
for (int i=1; i<=n; ++i) {
for (Node *p=G[i].head; p!=NULL; p=p->next) {
if (scc[i] != scc[p->u]) {
ees[scc[p->u]] = min(ees[scc[p->u]], p->w);///更新强连通分量之间的最小边权
}
}
}
int sum = 0;
for (int i=1; i<=sc; ++i) {
if (ees[i] != INT_MAX)  {///求这些最小边权和
sum += ees[i];
}
}
return sum;
}
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 u, v, w;
for (int i=0; i<m; ++i) {
scanf("%d%d%d", &v, &u, &w);
buildG(G, v+1, u+1, w);
buildG(NG, u+1, v+1, w);
}

printf("%d\n", kosaraju(n));
deleteG(G, n);
deleteG(NG, n);
}
return 0;
}

/**
*  hdu3639
*  题意:给出有向图,求出度为0的顶点,到达这些顶点的路径所经过的顶点数最多
*  解析:缩图,建立反向图,从入度为0的顶点dfs,dfs过程中,保存从该点出发,能够访问到的顶点数
**/
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

struct Node {
int u;
Node *next;
Node() {}
Node(int uu, Node *p=NULL) : u(uu), next(p){}
};
struct Graph {
Node *head;
Graph() {}
}G[5005], NG[5005], NNG[5005];
int scc_vs[5005];///存每个强连通子图的顶点个数
int dfn[5005];   ///顶点访问顺序
int scc[5005];   ///缩图
int ind[5005];   ///入度数
int vvs[5005];   ///缩点,反向图,存其他顶点可到该点的数目
bool vis[5005];  ///访问标记
int sc, cnt, vers, total;
///sc    统计强连通子图的个数和对同一个强连通子图中的顶点染成同一色
///cnt   ----
///vers  统计一个强连通子图的顶点个数
///total 把每个强连通子图看成是一个点,统计其他点可到该点的数目
void initG(int n) {///初始化图
for (int i=1; i<=n; ++i) {
G[i].head = NG[i].head = NNG[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) {
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; ///顶点k入栈
}
void dfs_two(int k) {
scc[k] = sc;   ///标记
vis[k] = true;
++vers;       ///该强连通子图的顶点数加1
for (Node *p=NG[k].head; p!=NULL; p=p->next) {
if (!vis[p->u])  {
dfs_two(p->u);
}
}
}
void dfs_three(int k) {
vis[k] = 1;
total += scc_vs[k];
for (Node *p=NNG[k].head; p!=NULL; p=p->next) {
if (!vis[p->u])  {
dfs_three(p->u);
}
}
}
int kosaraju(int n) {
sc = 0;
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));
for (int i=cnt; i>0; --i) {
if (!vis[dfn[i]]) {
++sc;
vers = 0;
dfs_two(dfn[i]);
scc_vs[sc] = vers;
}
}

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]) {
buildG(NNG, scc[p->u], scc[i]);
++ind[scc[i]];
}
}
}
for (int i=1; i<=sc; ++i)  {
vvs[i] = -1;
}
int maxx = -1;
for (int i=1; i<=sc; ++i) {
if (ind[i] == 0) {///对入度为0的点进行第三次DFS
total = 0;
for (int j=1; j<=sc; ++j)  {
vis[j] = false;
}
dfs_three(i);
vvs[i] = total;
maxx = max(maxx, vvs[i]);
}
}

return maxx;
}
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, t, cas = 0;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
initG(n);
int v, u;
for (int i=0; i<m; ++i) {
scanf("%d%d", &v, &u);
buildG(G, v+1, u+1);
buildG(NG, u+1, v+1);
}
int ans = kosaraju(n);
printf("Case %d: %d\n", ++cas, ans - 1);
int cs = 0;
for (int i=1; i<=n; ++i) {
if (vvs[scc[i]] == ans) {
if (cs != 0)  {
printf(" %d", i-1);
}else  {
cs = 1;
printf("%d", i-1);
}
}
}
deleteG(G, n);
deleteG(NG, n);
deleteG(NNG, sc);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息