UVALive 4287 Proving Equivalences(SCC、缩点+图的连通性)
2014-02-24 15:01
435 查看
题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2288
题目大意:有n个命题,先要证明他们全部等价,你的朋友已经做了m步等价关系的证明,让你算至少需要几部才能完成整个等价性的证明。
解题思路:比较基础的一道题吧。整个题目相当于给你m条单向边,问你最少补上几条边使得整个图强连通。很容易想到先缩点,整个图就是DAG了,然后对缩点后的SCC图,算出每个SCC团的入度和出度,那么要使整个图强连通,每个点的入度和出度都至少为1,所以答案就是max(入度为0的点个数,出度为0的点个数)。然后还有最重要的一点,也是这道题最恶心人的地方,那就是如果整个图先开始就是强连通的,那么答案就是0,不是1,要特判。
代码如下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int MAXN = 22222;
vector <int> G[MAXN];
int pre[MAXN],low[MAXN],sccno[MAXN];
int dfs_clock,scc_cnt;
stack <int> S;
void dfs(int u)
{
pre[u] = low[u] = ++dfs_clock;
S.push(u);
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i];
if(!pre[v])
{
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(!sccno[v])
low[u] = min(low[u],pre[v]);
}
if(low[u] == pre[u])
{
scc_cnt++;
for(;;)
{
int x = S.top();
S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}
void find_scc(int n)
{
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
dfs_clock = scc_cnt = 0;
for(int i = 0;i < n;i++)
if(!pre[i]) dfs(i);
}
int in[MAXN],out[MAXN];
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < n;i++)
G[i].clear();
for(int i = 0;i < m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
a--;
b--;
G[a].push_back(b);
}
find_scc(n);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int u = 0;u < n;u++)
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i];
if(sccno[u] != sccno[v])
{
out[sccno[u]]++;
in[sccno[v]]++;
}
}
int ans1 = 0,ans2 = 0;
for(int i = 1;i <= scc_cnt;i++)
{
if(in[i] == 0) ans1++;
if(out[i] == 0) ans2++;
}
int ans = max(ans1,ans2);
if(scc_cnt == 1) ans = 0;//特判,此题最阴险的地方!
printf("%d\n",ans);
}
return 0;
}
/*
2 2
1 2
2 1
*/
题目大意:有n个命题,先要证明他们全部等价,你的朋友已经做了m步等价关系的证明,让你算至少需要几部才能完成整个等价性的证明。
解题思路:比较基础的一道题吧。整个题目相当于给你m条单向边,问你最少补上几条边使得整个图强连通。很容易想到先缩点,整个图就是DAG了,然后对缩点后的SCC图,算出每个SCC团的入度和出度,那么要使整个图强连通,每个点的入度和出度都至少为1,所以答案就是max(入度为0的点个数,出度为0的点个数)。然后还有最重要的一点,也是这道题最恶心人的地方,那就是如果整个图先开始就是强连通的,那么答案就是0,不是1,要特判。
代码如下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int MAXN = 22222;
vector <int> G[MAXN];
int pre[MAXN],low[MAXN],sccno[MAXN];
int dfs_clock,scc_cnt;
stack <int> S;
void dfs(int u)
{
pre[u] = low[u] = ++dfs_clock;
S.push(u);
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i];
if(!pre[v])
{
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(!sccno[v])
low[u] = min(low[u],pre[v]);
}
if(low[u] == pre[u])
{
scc_cnt++;
for(;;)
{
int x = S.top();
S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}
void find_scc(int n)
{
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
dfs_clock = scc_cnt = 0;
for(int i = 0;i < n;i++)
if(!pre[i]) dfs(i);
}
int in[MAXN],out[MAXN];
int main()
{
int _;
scanf("%d",&_);
while(_--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i < n;i++)
G[i].clear();
for(int i = 0;i < m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
a--;
b--;
G[a].push_back(b);
}
find_scc(n);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int u = 0;u < n;u++)
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i];
if(sccno[u] != sccno[v])
{
out[sccno[u]]++;
in[sccno[v]]++;
}
}
int ans1 = 0,ans2 = 0;
for(int i = 1;i <= scc_cnt;i++)
{
if(in[i] == 0) ans1++;
if(out[i] == 0) ans2++;
}
int ans = max(ans1,ans2);
if(scc_cnt == 1) ans = 0;//特判,此题最阴险的地方!
printf("%d\n",ans);
}
return 0;
}
/*
2 2
1 2
2 1
*/
相关文章推荐
- UVAlive4287 Proving Equivalences(scc)
- UVALive 4287 Proving Equivalences(缩点)
- UVAlive4287 Proving Equivalences(scc)
- uvaLive_4287_Proving Equivalences(缩点)
- UVALive4287-- Proving Equivalences(SCC+Tarjan)
- UVALive - 4287 Proving Equivalences【强连通缩点】【Tarjan算法】
- UvaLive-4287- Proving Equivalences
- UVA 11324 - The Largest Clique(SCC缩点 + DP)
- UVALIVE 4287 Proving Equivalences (强连通分量+缩点)
- UVALive 4287 Proving Equivalence (强连通分量)
- 等价性证明(uvalive 4287)
- UVAlive11324 The Largest Clique(scc+dp)
- UVA 11324 有向图强连通分量缩点得SCC图,并在其上求最长路径
- 【 UVALive - 4287】Proving Equivalences (SCC缩点)
- UVALIVE 4287 Proving Equivalences Tarjan求强连通分量
- UVALive4287 hdu2767 hdu3836 强连通
- UVALive-4287 Proving Equivalences (有向图的强连通分量)
- UVALive - 4287 Proving Equivalences
- UvaLive 4287 Proving Equivalences 强连通缩点
- UvaLive-4287-Proving Equivalences