poj2553 The Bottom of a Graph
2011-07-17 10:03
405 查看
题意一开始理解有点小问题,题目大意是说如果一个点v能够到达w并且w也能到v则w和v都称为一个sink,题目要求从大到小输出图中所有的sink点,可能有人会对第二组数据不太理解,看一下这个图
显然1有一条边连接到2,如果1是sink点则2也要能够走到1,显然2是sink点因为它没有指向任何点,由此可以看出,只要一个强连通分量没有指向任何点,那么这个分量中的全部点就都是sink点,那么也就是说,只需要输出全部强连通分量出度为0的情况就可以了,记得要排序
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int size = 11000;
vector <int> mapp[size], remapp[size];
vector <int>comp[size];
vector <int>sccindex[size];
map <int, int> mak;
bool visited[size];
int num[size];
int belg[size];
int counter;
int n ;
int edge[5*size][2]; //0记录出点,1记录入点
void init()
{
for (int i = 0; i <= n; i ++){
mapp[i].clear(), remapp[i].clear(), comp[i].clear(), sccindex[i].clear();
}
mak.clear();
}
void dfs1(int v)
{
visited[v] = true;
for (int i = 0; i < mapp[v].size(); i ++){
int t = mapp[v][i];
if (!visited[t]){
dfs1(t);
}
}
num[++counter]= v;
}
int kk;
void dfs2(int v)
{
visited[v] = true;
sccindex[kk].push_back(v);//记录第kk个强连通分量中的点
mak[v] = kk;//记录第kk个点属于第几个强连通分量
for (int i = 0; i < remapp[v].size(); i ++){
int t = remapp[v][i];
if (!visited[t]){
belg[t] = kk;
dfs2(t);
}
}
}
void scc()
{
counter = 0;
memset(visited, false, sizeof(visited));
for (int i = 1; i <= n; i ++){
if (!visited[i]){
dfs1(i);
}
}
// cout<<"counter: "<<counter<<endl;
memset(visited, false ,sizeof(visited));
kk = 0;
for (int i = counter; i >= 1; i --){
int k = num[i];
if (!visited[k]){
visited[k] = true;
++ kk;
dfs2(k);
}
}
}
void compress()
{
for (int i = 1; i <= n; i ++){
for (int j = 0; j < mapp[i].size(); j ++){
if (belg[mapp[i][j]] != belg[i]){
comp[belg[i]].push_back(belg[mapp[i][j]]);
}
}
}
}
int main()
{
//freopen("IN.txt", "r", stdin);
//freopen("OUT.txt", "w", stdout);
int m;
while (scanf("%d", &n) != EOF && n){
scanf("%d", &m);
init();
int t;
int a, b;
for (int i = 0; i < m; i ++){
scanf("%d%d", &a, &b);
edge[i][0] = a;
edge[i][1] = b;
mapp[a].push_back(b);
remapp[b].push_back(a);
}
scc();
compress();
int OUT[size] = {0};
for (int i = 0; i < m; i ++){
a = mak[edge[i][0]], b = mak[edge[i][1]];//a,b表示每个出点入点所在的强连通分量位置
if (a != b){
OUT[a] ++;
}
}
int ans[size];
int id= 0;
for (int i = 1; i <= kk; i ++){
if (!OUT[i]){
for (int j = 0; j < sccindex[i].size(); j ++){
ans[id ++] = sccindex[i][j];
}
}
}
sort(ans, ans+id);
for (int i = 0; i < id; i ++){
if (i)printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
显然1有一条边连接到2,如果1是sink点则2也要能够走到1,显然2是sink点因为它没有指向任何点,由此可以看出,只要一个强连通分量没有指向任何点,那么这个分量中的全部点就都是sink点,那么也就是说,只需要输出全部强连通分量出度为0的情况就可以了,记得要排序
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int size = 11000;
vector <int> mapp[size], remapp[size];
vector <int>comp[size];
vector <int>sccindex[size];
map <int, int> mak;
bool visited[size];
int num[size];
int belg[size];
int counter;
int n ;
int edge[5*size][2]; //0记录出点,1记录入点
void init()
{
for (int i = 0; i <= n; i ++){
mapp[i].clear(), remapp[i].clear(), comp[i].clear(), sccindex[i].clear();
}
mak.clear();
}
void dfs1(int v)
{
visited[v] = true;
for (int i = 0; i < mapp[v].size(); i ++){
int t = mapp[v][i];
if (!visited[t]){
dfs1(t);
}
}
num[++counter]= v;
}
int kk;
void dfs2(int v)
{
visited[v] = true;
sccindex[kk].push_back(v);//记录第kk个强连通分量中的点
mak[v] = kk;//记录第kk个点属于第几个强连通分量
for (int i = 0; i < remapp[v].size(); i ++){
int t = remapp[v][i];
if (!visited[t]){
belg[t] = kk;
dfs2(t);
}
}
}
void scc()
{
counter = 0;
memset(visited, false, sizeof(visited));
for (int i = 1; i <= n; i ++){
if (!visited[i]){
dfs1(i);
}
}
// cout<<"counter: "<<counter<<endl;
memset(visited, false ,sizeof(visited));
kk = 0;
for (int i = counter; i >= 1; i --){
int k = num[i];
if (!visited[k]){
visited[k] = true;
++ kk;
dfs2(k);
}
}
}
void compress()
{
for (int i = 1; i <= n; i ++){
for (int j = 0; j < mapp[i].size(); j ++){
if (belg[mapp[i][j]] != belg[i]){
comp[belg[i]].push_back(belg[mapp[i][j]]);
}
}
}
}
int main()
{
//freopen("IN.txt", "r", stdin);
//freopen("OUT.txt", "w", stdout);
int m;
while (scanf("%d", &n) != EOF && n){
scanf("%d", &m);
init();
int t;
int a, b;
for (int i = 0; i < m; i ++){
scanf("%d%d", &a, &b);
edge[i][0] = a;
edge[i][1] = b;
mapp[a].push_back(b);
remapp[b].push_back(a);
}
scc();
compress();
int OUT[size] = {0};
for (int i = 0; i < m; i ++){
a = mak[edge[i][0]], b = mak[edge[i][1]];//a,b表示每个出点入点所在的强连通分量位置
if (a != b){
OUT[a] ++;
}
}
int ans[size];
int id= 0;
for (int i = 1; i <= kk; i ++){
if (!OUT[i]){
for (int j = 0; j < sccindex[i].size(); j ++){
ans[id ++] = sccindex[i][j];
}
}
}
sort(ans, ans+id);
for (int i = 0; i < id; i ++){
if (i)printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
相关文章推荐
- POJ 2553 The Bottom of a Graph
- POJ 2553 The Bottom of Graph 强连通图题解
- POJ 2553——The Bottom of a Graph(强连通分量)
- [tarjan] poj 2553 The Bottom of a Graph
- poj 2553 The Bottom of a Graph(强连通、缩点、出入度)
- POJ 2553 The Bottom of a Graph(Tarjan,强连通分量)
- poj 2553 The Bottom of a Graph(强连通分量)
- [poj][2553][The Bottom of a Graph]
- poj 2186【Popular Cows】1236【Network of Schools】2553【The Bottom of a Graph】
- POJ 2553--The Bottom of a Graph【scc缩点构图 && 求出度为0的scc && 输出scc中的点】
- POJ 2553 The Bottom of a Graph .
- poj2553 The Bottom of a Graph
- poj2553——The Bottom of a Graph
- poj 2553 The Bottom of a Graph【强连通分量求汇点个数】
- [poj 2553]The Bottom of a Graph[Tarjan强连通分量]
- POJ 2553 The Bottom of a Graph (Trajan 强连通分量 缩点)
- poj - 2186 Popular Cows && poj - 2553 The Bottom of a Graph (强连通)
- POJ 2553 The Bottom of a Graph
- poj--2553--The Bottom of a Graph (scc+缩点)
- POJ 2553 The Bottom of a Graph 【scc tarjan】