Friendships(构造)

题意

构造满足如下要求的图:

  • 图是简单的,并且是连通的
  • 总共有\(N\)个点,并且编号为\(1, 2, \dots, N\)
  • \(M\)条边,并且每条边的长度为\(1\)
  • 存在正好\(K\)对节点\((i, j)\),满足最短距离为\(2\)

构造一个满足要求的图,并输出所有的边;如果不存在这样的图,那么输出\(-1\)

数据范围

\(2 \leq N \leq 100\)
\(0 \leq K \leq \frac{N(N - 1)}{2}\)

思路

从特殊的图的性质入手。首先考虑树。

如果是一棵两层的树,第一层节点数为\(1\),第二层节点数为\(N - 1\)。那么有\(\frac{(N - 1)(N - 2)}{2}\)对节点满足最短路为\(2\)

如果将第二层的一部分节点变成第二层其他节点的子节点,通过推导可以发现,满足最短距离为\(2\)的点对的个数不多于\(\frac{(N - 1)(N - 2)}{2}\)

因此,在树中,满足最短距离为\(2\)的点对的个数最多为\(\frac{(N - 1)(N - 2)}{2}\)

再考虑图的情况,即往树上加边。在两层的树上,每加一条边,满足最短距离为\(2\)的点对的个数减\(1\)。如果第二层\(N - 1\)个点两两加边,那么点对个数为\(0\)

因此,我们发现,通过对两层树进行加边,满足要求的点对个数在\([0, \frac{(N - 1)(N - 2)}{2}]\)之间连续变化。

我们可以得出做法:如果\(k > \frac{(N - 1)(N - 2)}{2}\),则无解;否则,先建立两层树,然后对\(k - \frac{(N - 1)(N - 2)}{2}\)个点对加边。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

typedef pair<int, int> pii;

int n, k;
vector<pii> ans;

int main()
{
    scanf("%d%d", &n, &k);
    int mx = (n - 1) * (n - 2) / 2;
    if(mx < k) {
        printf("-1\n");
    }
    else {
        for(int i = 2; i <= n; i ++) {
            ans.push_back({1, i});
        }
        int res = mx - k;
        for(int i = 2; i <= n; i ++) {
            if(!res) break;
            for(int j = i + 1; j <= n; j ++) {
                ans.push_back({i, j});
                res --;
                if(!res) break;
            }
        }
        printf("%d\n", ans.size());
        for(auto p : ans) {
            printf("%d %d\n", p.first, p.second);
        }
    }
    return 0;
}
posted @ 2022-06-04 10:59  pbc的成长之路  阅读(23)  评论(0)    收藏  举报