Watch Where You Step(拓扑排序)

题目描述
You are an employee at the local zoo and have recently been promoted from excretory extraction to over-seeing the layout of all the sidewalks throughout the property. Currently all the sidewalks are 1-way, and the zoo is set up in various zones. Each zone is made up of a set of attractions (elephant enclosure, lizard house, etc.), and within any one zone you can get from any attraction to any other attraction in the zone using one or more sidewalks. Once you take a sidewalk from one zone to another you can never return to the zone you left. However, it is possible to walk to every zone in a single visit to the zoo. The original designers thought this arrangement was very important to help control the flow of visitors to the zoo.
The members of the board of directors have come to you with a problem. They agree with the original designers in the use of zones, but they feel that more one-way sidewalks could be included to make the zoo a little more patron-friendly. They would like you to figure out the maximum number of sidewalks that could be added so as not to introduce a path between any two attractions which didn’t have one between them before.
For example, consider the small zoo shown in figure J.1, with 7 attractions labeled 1 (the “Camel Castle”) through 7 (the “Hippo Hippodrome”). Currently attractions 1, 2, 3 and 4 form one zone and 5, 6 and 7 form another. You can add sidewalks from 1, 2, 3 or 4 to either 5, 6 or 7, but adding a sidewalk from (say) 7 to 1 would allow patrons to get from 7 to 1, which was impossible previously. Note that you can also add sidewalks between all attractions within a zone which don’t already exist (for example, from 1 to 3 or from 2 to 4). The total number of possible new sidewalks for this zoo would be 21.

figure J.1: Sample zoo. This example corresponds to Sample Input 1.

输入
Input starts with a line containing an integer n (1 ≤ n ≤ 2 500), the number of attractions, labeled 1 to n.
After this are n lines each containing n integers. If the jth integer on the ith of these lines is a 1 it indicates that there is a one-way sidewalk from attraction i to attraction j; otherwise this integer will be a 0 indicating no such sidewalk is present. There is never a sidewalk from an attraction to itself.

输出
Display the maximum number of new one-way sidewalks that could be added to the zoo.

样例输入
7
0 1 0 0 0 0 0
0 0 1 0 1 0 0
1 0 0 1 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 1 0
0 0 0 0 0 0 1
0 0 0 0 1 0 0

样例输出
21

思路
对每个联通块,将其中的点全部连接起来需要n*(n-1)条边,将其全部链接起来需要v[i]*v[j]条边(v[i]为每个块中的点数),为避免重复建边,需要对每个联通块排序,因此对整个图进行两次dfs,一次dfs获得拓扑序,一次dfs获得每个联通块中的点,最后对每个块按序处理即可

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=3000;
const int M=10005;
const int INF=0x3f3f3f3f;
const ll mod=998244353;
typedef pair<int,int>P;


vector<int>tE[N],fE[N];
bool vis[N],viss[N];
int n,cnt;

void add(int u,int v)
{
    tE[u].push_back(v);
    fE[v].push_back(u);
    cnt++;
}

stack<int>s;
void dfs1(int u)
{
    if(vis[u]) return;
    vis[u]=true;
    for(int i=0;i<tE[u].size();i++)
    {
        int v=tE[u][i];
        if(!vis[v]) dfs1(v);
    }
    s.push(u);
}

int dfs2(int u)
{
    if(viss[u]) return 0;
    viss[u]=true;
    int ret=1;
    for(int i=0;i<fE[u].size();i++)
    {
        int v=fE[u][i];
        if(!viss[v]) ret+=dfs2(v);
    }
    return ret;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            int t;
            scanf("%d",&t);
            if(t) add(i,j);
        }
    }
    for(int i=0;i<n;i++) if(!vis[i]) dfs1(i);
    vector<int>tot;
    for(int i=0;i<n;i++)
    {
        int tmp=s.top();
        s.pop();
        if(!viss[tmp]) tot.push_back(dfs2(tmp));
    }
    int ans=0;
    for(int i=0;i<tot.size();i++)
    {
        ans+=tot[i]*(tot[i]-1);
        for(int j=i+1;j<tot.size();j++) ans+=tot[i]*tot[j];
    }
    printf("%d\n",ans-cnt);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值