题目: https://vjudge.net/problem/UVA-247
思路:用Floyd算法求出闭包传递,即在有向图中,两点间是否连通。
然后用BFS也好DFS也好并查集也好把同一连通分支的点都输出即可,我用的BFS。
Floyd算法核心代码只有几行,实质就是枚举中转点K,看是否有点I经过K点到J比直接从I到J路程要短,不断更新。
Floyd核心代码:
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (pic[i][k] != INF && pic[k][j] != INF)
{
pic[i][j] = min(pic[i][j], pic[i][k] + pic[j][k]);
}
}
}
}
而闭包传递只需要改成
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (pic[i][k] && pic[k][j])
{
pic[i][j] = true;
}
}
}
}
题目代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 100;
int n;
bool pic[maxn][maxn];
map<string, int> name;
string order[maxn];
int ind;
void Floyd()
{
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (pic[i][k] && pic[k][j])
{
pic[i][j] = true;
}
}
}
}
}
void init()
{
ind = 1;
name.clear();
for (int i = 0; i < maxn; i++)
{
order[i].clear();
}
memset(pic, false, sizeof(pic));
for (int i = 1; i <= n; i++)
{
pic[i][i] = true;
}
}
int cases = 1;
void bfsprint()
{
if (cases != 1)
{
printf("\n");
}
printf("Calling circles for data set %d:\n", cases++);
bool vis[maxn] = { 0 };
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
queue<int> q;
q.push(i);
vis[i] = true;
while (!q.empty())
{
int u = q.front();
q.pop();
if (u != i)
{
printf(", ");
}
printf("%s", order[u].c_str());
for (int j = 1; j <= n; j++)
{
if (pic[u][j] && pic[j][u] && !vis[j])
{
vis[j] = true;
q.push(j);
}
}
}
printf("\n");
}
}
}
int main()
{
int m;
while (scanf("%d%d", &n, &m) && (n || m))
{
init();
while (m--)
{
char s1[maxn] = { 0 }, s2[maxn] = { 0 };
scanf("%s%s", s1, s2);
string a(s1), b(s2);
if (name[a] == 0)
{
order[ind] = a;
name[a] = ind++;
}
if (name[b] == 0)
{
order[ind] = b;
name[b] = ind++;
}
pic[name[a]][name[b]] = true;
}
Floyd();
bfsprint();
}
return 0;
}