題目大意
有編號爲1 ~ c 的 c 個點,在點上建有向邊,如果有邊 a -> b ,則a一定小於b。
因此圖爲DAG。
問有多少點對 (a, b),存在兩條路分別從1到達a和b,並且在兩條路上只有1同時出現。
假設1和其他點都滿足條件。
思路
計算所有不滿足條件的點對數。
編號從小到大對點進行標記,如果前驅節點的標號相同,此節點也標記相同的號,如果不同就標記爲自己的序號。
邊界條件:如果前驅節點中有1則標記自己的序號。
標記完後,節點會被分爲若干組,標號的意義是: 此節點通往節點1的多條路徑都必須經過的點。
標號相同的點對一定不滿足條件。
ans = Comb(c, 2) - ∑ Comb(ai, 2)
ai 爲各組的節點數
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 1010
using namespace std;
typedef long long ll;
vector<int> pre[MAXN];
int cnt[MAXN], bk[MAXN], c, p;
int u, v;
ll comb(int x)
{
return (ll)x * (x - 1) / 2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
while (scanf("%d %d", &c, &p) != EOF)
{
mem(cnt, 0);
mem(bk, 0);
for (int i = 1; i <= c; i++)
pre[i].clear();
for (int i = 0; i < p; i++)
{
scanf("%d %d", &u, &v);
pre[v].push_back(u);
}
ll ans = 0;
for (int i = 2; i <= c; i++)
{
for (int j = 0; j < pre[i].size(); j++)
{
int fa = pre[i][j];
if (fa == 1)
{
bk[i] = i;
break;
}
if (!bk[i])
bk[i] = bk[fa];
else
{
if (bk[i] != bk[fa])
{
bk[i] = i;
break;
}
}
}
cnt[bk[i]]++;
}
for (int i = 2; i <= c; i++)
{
if (cnt[i])
ans += comb(cnt[i]);
}
printf("%lld\n", comb(c) - ans);
}
return 0;
}