题意:
给定一个有向无环图,判断是否任意两点都能通过其中一点到达另外一点。
思路:
首先缩点,每个强连通内的点都是相互可达的,所以再对缩点后的图进行处理,易知道若要满足条件那么必然会存在一条覆盖所有点的链,那么链的起点必定是入度为0的一点,终点必定是出度为0的一点。经分析,该条链走的时候不能"分叉",然后就可以联想到拓扑序去判断每次是否存在多个入度为0的点。
当然这题的数据并不是很强,可以通过dfs搜索这条长链来进行判断。
代码1:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll _inf = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const int maxn = 1005;
const int maxm = 6005;
struct node
{
int u, v, next;
} edge[maxm];
int no, head[maxn];
int index, low[maxn], dfn[maxn], S[maxn], top, vis[maxn];
int deg[maxn];
int bcc[maxn], cnt;
bool G[maxn][maxn];
queue<int> q;
int n, m;
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
index = top = 0; cnt = 0;
memset(dfn, 0, sizeof dfn);
memset(bcc, 0, sizeof bcc);
memset(deg, 0, sizeof deg);
memset(G, 0, sizeof G);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++index;
S[++top] = u;
vis[u] = 1;
for(int k = head[u]; k != -1; k = edge[k].next)
{
int v = edge[k].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
++cnt;
do
{
bcc[S[top]] = cnt;
vis[S[top--]] = 0;
}
while(S[top+1] != u);
}
}
bool work()
{
if(cnt == 1) return 1;
while(!q.empty()) q.pop();
for(int i = 1; i <= cnt; ++i)
if(!deg[i]) q.push(i);
if(q.size() > 1) return 0;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 1; i <= cnt; ++i)
{
if(!G[u][i]) continue;
--deg[i];
if(!deg[i]) q.push(i);
}
if(q.size() > 1) return 0;
}
return 1;
}
int main()
{
//freopen("in.txt", "r", stdin);
int t, u, v;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m); init();
for(int i = 1; i <= m; ++i)
{
scanf("%d %d", &u, &v);
add(u, v);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 0; i < no; ++i)
{
int u = edge[i].u, v = edge[i].v;
if(bcc[u] != bcc[v] && !G[bcc[u]][bcc[v]])
{
G[bcc[u]][bcc[v]] = 1;
++deg[bcc[v]];
}
}
if(work()) puts("I love you my love and our love save us!");
else puts("Light my fire!");
}
return 0;
}
代码2:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll _inf = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const int maxn = 1005;
const int maxm = 6005;
struct node1
{
int u, v, next;
} edge[maxm];
struct node
{
int v, w;
};
int no, head[maxn];
int index, low[maxn], dfn[maxn], S[maxn], top, vis[maxn];
int bcc[maxn], cnt;
bool G[maxn][maxn];
queue<node> q;
int n, m, ans;
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
index = top = 0; cnt = 0;
memset(dfn, 0, sizeof dfn);
memset(bcc, 0, sizeof bcc);
memset(G, 0, sizeof G);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++index;
S[++top] = u;
vis[u] = 1;
for(int k = head[u]; k != -1; k = edge[k].next)
{
int v = edge[k].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
++cnt;
do
{
bcc[S[top]] = cnt;
vis[S[top--]] = 0;
}
while(S[top+1] != u);
}
}
void dfs(int u, int count)
{
for(int i = 1; i <= cnt; ++i)
{
if(!G[u][i] || vis[i]) continue;
vis[i] = 1;
dfs(i, count+1);
vis[i] = 0;
if(ans == cnt) return;
}
ans = max(ans, count);
}
int main()
{
//freopen("in.txt", "r", stdin);
int t, u, v;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m); init();
for(int i = 1; i <= m; ++i)
{
scanf("%d %d", &u, &v);
add(u, v);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 0; i < no; ++i)
{
int u = edge[i].u, v = edge[i].v;
if(bcc[u] != bcc[v] && !G[bcc[u]][bcc[v]])
{
G[bcc[u]][bcc[v]] = 1;
}
}
ans = 0;
memset(vis, 0, sizeof vis);
for(int i = 1; i <= cnt; ++i)
{
vis[i] = 1;
dfs(i, 1);
vis[i] = 0;
if(ans == cnt) break;
}
if(ans != cnt) puts("Light my fire!");
else puts("I love you my love and our love save us!");
}
return 0;
}
继续加油~