【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6165
题目意思
给你一张有向图,问你图中任意两点是否相通(只要AB之间有一条路就可以了)
解题思路
两种解法:
1.利用搜索查询每个点能到达的其他点,最后判断任意两点之间是否有路就可以了
2.使用强连通缩点,也就是把图中的环看做一个点(环的任意两点是可以到达的),然后建立新图根据出入度来判断新图任意两点是否相通。(因为它要求的是任意两点任何一点能够到达另外一点,所以就如果入度为0的点的个数大于等于两个,那就是不满足的。)
代码部分
dfs:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn=1e3+5;
int n,m,p;
vector<int>M[maxn]; ///图
bool vis[maxn][maxn]; ///标记是否相通
void dfs(int u)
{
vis[p][u]=true;
for (int i=0;i<M[u].size();i++)
{
if (!vis[p][M[u][i]])
dfs(M[u][i]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
bool fa=true;
scanf("%d %d ",&n,&m);
for (int i=1;i<=n;i++)
M[i].clear();
memset(vis,0,sizeof(vis));
for (int i=0; i < m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
M[u].push_back(v);
}
for (int i=1;i<=n;i++)
{
p=i;
dfs(i);
}
for (int i=1;i<=n;i++)
{
for (int j=i;j<=n;j++)
{
if (!vis[i][j]&&!vis[j][i])
{
fa=false;
break;
}
}
}
if (!fa)
cout<<"Light my fire!"<<endl;
else cout<<"I love you my love and our love save us!"<<endl;
}
return 0;
}
强连通:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int dfn[maxn];//dfs顺序
int low[maxn];
int index1;//记录时间的标号
bool state[maxn];//是否在栈里.
stack<int>s;
vector<int>G[maxn];
vector<int>g[maxn];
int cnt[maxn];
int num[maxn], du[maxn];//num数组不一定要,各个强连通分量包含点的个数,数组编号1~cnt
int scc,flag;//scc为强连通分量的个数
int vis[maxn];
void init()
{
scc = 0,flag=0;
memset(du, 0, sizeof(du));
memset(state, false, sizeof(state));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(cnt, 0, sizeof(cnt));
memset(vis, false, sizeof(vis));
memset(num, 0, sizeof(num));
while(!s.empty())
s.pop();
for(int i = 0; i < maxn; i++)
{
G[i].clear();
g[i].clear();
}
}
void tarjan(int u)//tarjan 处理强连通分量。
{
dfn[u] = low[u] = ++index1;
s.push(u);
state[u] = true;
vis[u] = true;
for(int i = 0; i < G[u].size(); i++)
{
int w = G[u][i];
if(!vis[w])
{
tarjan(w);
low[u] = min(low[w], low[u]);
}
else if(state[w])
{
low[u] = min(low[u], dfn[w]);
}
}
if(low[u] == dfn[u])
{
scc++;
for(;;)
{
int x = s.top();
s.pop();
cnt[x] = scc;//标记v点属于哪个强连通分量
num[scc]++;//记录这个强连通分量有多少个点组成
state[x] = false;
if(x == u)break;
}
}
}
void topsort()
{
queue<int>q;
int sizz=0;
for(int i=1;i<=scc;i++)
{
if(!du[i])
{
sizz++;
q.push(i);
}
}
if(sizz>=2) flag=1;//如果刚缩点后就有两个以上度为0的坑定不可以啊
while(!q.empty()&&!flag)
{
int u=q.front();
q.pop();
int siz=0;
for(int i=0;i<g[u].size()&&!flag;i++)
{
int to=g[u][i];
du[to]--;
if(du[to]==0)
{
siz++;
q.push(to);
}
if(siz>=2) flag=1;
}
if(flag) break;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(int i=1;i<=n;i++)//新建图
{
int u=cnt[i];
for(int j=0;j<G[i].size();j++)
{
int v=cnt[G[i][j]];
if(u!=v)
{
g[u].push_back(v);
du[v]++;//入度
}
}
}
topsort();
if(flag) puts("Light my fire!");
else puts("I love you my love and our love save us!");
}
return 0;
}