HDU-6165 FFF at Valentine - 2017 Multi-University Training Contest - Team 9(强连通分量缩点+拓扑)

题意:

给定一个有向无环图,判断是否任意两点都能通过其中一点到达另外一点。

思路:

首先缩点,每个强连通内的点都是相互可达的,所以再对缩点后的图进行处理,易知道若要满足条件那么必然会存在一条覆盖所有点的链,那么链的起点必定是入度为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;
}


继续加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值