题目描述:小红希望你构造一个无向连通图,满足共有
n
n
n个点
m
m
m条边,且
i
i
i号节点到1号节点的最短路长度怡好为
a
i
a_i
ai。你能帮帮她
吗?
输入描述:
第一行输入两个正整数
n
,
m
n,m
n,m, 代表构造的图的点数和边数。
第二行输入
n
n
n个整数
a
i
a_i
ai,代表
i
i
i号节点到 1 号节点的最短路。
1
≤
n
,
m
≤
1
0
5
1\leq n,m\leq10^5
1≤n,m≤105
a
1
=
0
a_1=0
a1=0,对于
i
≥
2
i\geq2
i≥2,1
≤
a
i
≤
n
−
1
\leq a_i\leq n-1
≤ai≤n−1
输出描述:
如果无解,请输出 -1。
否则输出
m
m
m行,每行输出两个正整数
u
,
v
u,v
u,v,代表节点
u
u
u和节点
v
v
v有一条边连接。
请务必保证不含重边和自环,否则将直接判为答案错误。
示例一:
输入:
3 3 0 1 1
输出:
1 2 2 3 3 1
示例二:
输入:
3 3 0 1 2
输出:
-1
分析:要满足,
i
i
i号节点到1号节点的最短路长度怡好为
a
i
a_i
ai,则可以将
a
i
a_i
ai看成每一层,这其中每一层可能会有多个节点,首先要求m>=n-1,此时才能连通,同时,可以先将每一层的0号节点连接起来,看看有没有多余的边,如果有多余的边,我们就要将其分配掉,怎么分配不会破坏最短路的性质呢,兄弟节点之间的相连和某一层节点到下一层节点相连不会,最后如果能连的边都连起来了边数依旧小于m,则输出-1
下面是完整代码
#include<iostream>
#include<queue>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#include<set>
#include<cmath>
#include<stack>
#include<random>
#include<ctime>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define fi first
#define se second
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define __int128_t int128
using namespace std;
typedef pair<int, int> PII;
typedef pair<ll, int> PLI;
int dx[4] = {-1,0,1,0},dy[4] = {0,1,0,-1};
const int N = 1e5 + 10;
int a[N];
vector<int> g[N];
int main() {
ios
int n, m;
cin >> n >> m;
int ma = 0;
for (int i = 1; i <= m; i++) {
cin >> a[i];
ma = max(a[i], ma);
g[a[i]].push_back(i);
}
if (m < n - 1) {
cout << -1 << '\n';
return 0;
}
vector<PII> v;
for (int i = 1 ; i <= ma; i++) {
if (g[i].empty()) {
cout << -1 << '\n';
return 0;
}
if(i > 1) {
for (auto j : g[i]) {
v.push_back({g[i - 1][0], j});
}
}
}
if (v.size() < m) {
for (int i = 1; i <= ma; i++) {
for (size_t j = 0; j < g[i].size(); j++) {
for (size_t k = j + 1; k < g[i].size(); k++) {
v.push_back({g[i][j], g[i][k]}); // 连接兄弟节点
if (v.size() == m) break;
}
if (v.size() == m) break;
}
if (v.size() == m) break;
}
for (int i = 1; i <= ma; i++) {
for (size_t j = 1; j < g[i].size(); j++) {
if (i < ma) {
for (auto k : g[i + 1]) {
v.push_back({g[i][j], k}); // 连接下一层
if (v.size() == m) break;
}
}
if (v.size() == m) break;
}
if (v.size() == m) break;
}
}
if (v.size() < m) {
cout << -1 << '\n';
return 0;
}
for (auto i : v) {
cout << i.first << " " << i.second << '\n';
}
return 0;
}