您的位置:首页 > 其它

Gym 101246.G - Revolutionary Roads(思维)

2017-10-16 20:33 351 查看
>题意:给你一张有向图,exactly将一条边变成双向边,问你改变后这个图中最大的强联通分量包含几个点,记录为w。输出w,并统计出所有改变后最大强联通分量包含的顶点数等于w的边是哪些,输出出来。(vs≤1000,es≤20000)

思路:

  这种更改一条边,一个点的题,往往是枚举边,那么枚举边以后,我们考虑对于u->v这条边,把它改为双向边。

  然后我们再来考虑一个点w。如果u到w可达,w到v可达,那么改为双向边以后,w就属于这个强联通分量。所以预处理一下任意两点之间的可达关系,用邻接矩阵存一下。然后枚举边去改变即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000 + 5;
vector<int>G[maxn];
bool ma[maxn][maxn];
int vis[maxn];
void dfs(int cur, int st)
{
ma[st][cur] = vis[cur] = 1;
for(auto o : G[cur])    if(!vis[o])
{
dfs(o, st);
}
}
pair<int, int>edge[20000 + 5];
int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
int vs, es;
scanf("%d%d", &vs, &es);
if(es == 0)
{
printf("1\n0\n");
return 0;
}
for(int i = 1; i <= es; i++)
{
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
edge[i] = {u, v};
}
for(int i = 1; i <= vs; i++)
{
memset(vis, 0, sizeof(vis));
dfs(i, i);
}

vector<int>vec;
int mx = 0;
for(int i = 1; i <= es; i++)
{
int u = edge[i].first, v = edge[i].second;
int cnt = 2;
for(int j = 1; j <= vs; j++)
{
if(u == j || v == j)    continue;
if(ma[u][j] && ma[j][v])    cnt++;
}
if(cnt > mx)    mx = cnt, vec.clear(), vec.push_back(i);
else if(cnt == mx)  vec.push_back(i);
}
printf("%d\n", mx);
printf("%d\n", vec.size());
for(int i = 0; i < vec.size(); i++)
{
printf("%d%c", vec[i], " \n"[i + 1 == vec.size()]);
}
return 0;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: