Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
First, do the boring graph-theory tax: the number of odd-degree vertices is always even. So if is odd, the answer is instantly No.
Think in terms of bridge-blocks. If you delete all bridges, the remaining connected components become nodes of a tree, and that tree has exactly edges.
A bridge-less simple connected component is either a single vertex or has at least vertices. This nukes the sneaky case : you would need blocks on vertices, meaning one block has size , which is impossible.
For the main construction, use one large bridge-less component of size , and make the other vertices singleton bridge-blocks. Then all bridges are just edges in a tree connecting these blocks.
Inside a large block, start with a cycle: all degrees are even and no edge is a bridge. Every added chord toggles exactly two endpoint parities and still creates no bridges. So the whole problem becomes choosing how many odd vertices come from singleton blocks and how many come from the core.
Key Idea
Do not try to place bridges one by one in the original graph. That gets messy fast. Compress the graph by deleting all bridges. The remaining connected pieces are bridge-less components, and the bridges between those pieces form a tree.
So we build the graph from the top down:
Then we tune parity. Bridges flip degrees at their endpoints, while chords inside the core flip pairs of vertices. Nice and mechanical. No wizardry, just graph plumbing.
Necessary Conditions
The number of odd-degree vertices in any graph is even. So odd is impossible.
If , the only connected simple graph has no edges, so only works.
If , every edge is a bridge, so the graph is a tree. A tree on at least two vertices always has at least two odd-degree vertices, and every even from to is constructible.
If , the answer is always No. After deleting bridges, we would have components. A non-singleton bridge-less simple connected component needs at least vertices, so compared to singleton components it needs at least two extra vertices. But we only have one extra vertex. That means some component would have size , and a simple connected graph on two vertices has one edge, which is a bridge. So nope.
If , then is impossible. The bridge-block tree has at least two leaves. A leaf block has exactly one bridge incident to it, so its final degree parity sum is odd, meaning it contributes at least one odd vertex.
Tree Case
For , construct a tree with exactly odd vertices.
Use a path as a spine. A path already gives two odd endpoints. If we need more odd vertices, attach leaves to one suitable spine vertex. Attaching a leaf makes the leaf odd and flips the attachment vertex. Choosing the attachment point correctly keeps the total exactly .
Concretely:
leaves = k - 2,s = n - leaves,That gives exactly odd vertices and all edges are bridges.
Bridge-Less Core
For a core of size , we can realize any even-sized set of odd vertices.
Start with a cycle through all vertices. Every vertex has degree , and no edge is a bridge. Then pair up the vertices that should become odd and add one chord for each pair. Each chord toggles exactly its two endpoints. Since adding edges cannot create bridges, the core stays bridge-less.
One small implementation detail: a chord cannot duplicate a cycle edge. So we choose the cycle order so paired vertices are not adjacent. If there is one pair, put two other vertices between its endpoints around the cycle. If there are multiple pairs, put all first endpoints, then all second endpoints, then all unused vertices. This avoids duplicate edges cleanly.
For , the only bridge-less simple connected core is a triangle, so internally it contributes no odd vertices. Odd vertices in the triangle can only come from bridge endpoints attached to its vertices.
Main Non-Tree Construction
Now assume . Let
.
Use vertices as the core. The remaining vertices are singleton bridge-blocks.
We choose three numbers:
We need:
Why those parity rules? Because in a tree, the parity of a block's bridge-degree determines the parity of the number of odd vertices contributed by that block. Internal edges only toggle vertices in pairs.
The code just searches over and finds a compatible . This is not a guess. For , the core can provide any with the required parity. For , the code checks the real triangle limitation directly.
Building the Block Tree
Once and are chosen, we need a tree on block-nodes:
0 is the core,1..b are singleton vertices.Set the core degree to .
For singleton blocks:
A valid degree sequence is easy:
The sum becomes exactly , so it is a valid tree degree sequence. Then we build the actual tree using the standard Prufer-code construction.
Every edge of this block tree becomes a bridge in the final graph. Singleton-singleton block edges become normal edges between those singleton vertices. Core-singleton block edges attach that singleton vertex to some core vertex.
Finishing Parity in the Core
For , attach every bridge incident to the core at core vertex . If is odd, vertex gets flipped by bridges; if is even, it does not.
Let be the desired final odd set in the core, with size . The internal core must therefore have odd set:
if is even, and with vertex toggled if is odd.
The size of is even, so the cycle-plus-chords construction realizes it.
For , use a triangle and distribute the bridge endpoints among triangle vertices so exactly triangle vertices receive an odd number of bridges.
Complexity
Everything is linear. The graph has at most about edges in the core construction, plus bridges, so it easily satisfies . Runtime is because of the priority queue used for Prufer construction, and the sum of is only .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
void addCore(int s, const vector<int>& odd, vector<pair<int,int>>& edges) {
vector<pair<int,int>> pairs;
for (int i = 0; i < (int)odd.size(); i += 2) pairs.push_back({odd[i], odd[i + 1]});
vector<int> order;
if (pairs.empty()) {
for (int i = 1; i <= s; i++) order.push_back(i);
} else if ((int)pairs.size() == 1) {
int a = pairs[0].first, b = pairs[0].second;
vector<int> other;
for (int i = 1; i <= s; i++) if (i != a && i != b) other.push_back(i);
order = {a, other[0], b, other[1]};
for (int i = 2; i < (int)other.size(); i++) order.push_back(other[i]);
} else {
vector<int> used(s + 1, 0);
for (auto [a, b] : pairs) {
order.push_back(a);
used[a] = used[b] = 1;
}
for (auto [a, b] : pairs) order.push_back(b);
for (int i = 1; i <= s; i++) if (!used[i]) order.push_back(i);
}
for (int i = 0; i < s; i++) edges.push_back({order[i], order[(i + 1) % s]});
for (auto e : pairs) edges.push_back(e);
}
void buildTreeCase(int n, int k, vector<pair<int,int>>& edges) {
int leaves = k - 2;
int s = n - leaves;
for (int i = 1; i < s; i++) edges.push_back({i, i + 1});
int attach = (s >= 3 ? 2 : 1);
for (int v = s + 1; v <= n; v++) edges.push_back({attach, v});
}
vector<pair<int,int>> buildBlockTree(int b, int d, int x) {
vector<int> deg(b + 1);
deg[0] = d;
for (int i = 1; i <= b; i++) deg[i] = (i <= x ? 1 : 2);
deg[1] += x - d;
vector<int> cur = deg, prufer;
priority_queue<int, vector<int>, greater<int>> leaves;
for (int i = 0; i <= b; i++) {
for (int j = 0; j < deg[i] - 1; j++) prufer.push_back(i);
if (deg[i] == 1) leaves.push(i);
}
vector<pair<int,int>> res;
for (int v : prufer) {
int leaf = leaves.top();
leaves.pop();
res.push_back({leaf, v});
cur[leaf]--;
if (--cur[v] == 1) leaves.push(v);
}
int a = leaves.top(); leaves.pop();
int c = leaves.top(); leaves.pop();
res.push_back({a, c});
return res;
}
bool buildNonTree(int n, int k, int b, vector<pair<int,int>>& edges) {
int s = n - b;
int d = -1, q = -1;
for (int cand = 1; cand <= b && d == -1; cand++) {
if (s == 3) {
for (int qq = 0; qq <= 3; qq++) {
int x = k - qq;
if (x < cand || x > b) continue;
if ((x & 1) != (cand & 1)) continue;
if ((qq & 1) != (cand & 1)) continue;
if (qq != 0 && qq > cand) continue;
d = cand;
q = qq;
break;
}
} else {
int lo = max(0, k - b);
int hi = min(s, k - cand);
if (lo > hi) continue;
int qq = lo;
if ((qq & 1) != (cand & 1)) qq++;
if (qq <= hi) {
d = cand;
q = qq;
}
}
}
if (d == -1) return false;
int x = k - q;
auto blockEdges = buildBlockTree(b, d, x);
vector<int> coreNeighbors;
for (auto [a, c] : blockEdges) {
if (a == 0 || c == 0) coreNeighbors.push_back(a ^ c);
else edges.push_back({s + a, s + c});
}
if (s == 3) {
edges.push_back({1, 2});
edges.push_back({2, 3});
edges.push_back({3, 1});
for (int i = 0; i < (int)coreNeighbors.size(); i++) {
int endpoint = (i < q ? i + 1 : 1);
edges.push_back({endpoint, s + coreNeighbors[i]});
}
} else {
vector<int> want(s + 1, 0);
for (int i = 1; i <= q; i++) want[i] = 1;
if (d & 1) want[1] ^= 1;
vector<int> odd;
for (int i = 1; i <= s; i++) if (want[i]) odd.push_back(i);
addCore(s, odd, edges);
for (int v : coreNeighbors) edges.push_back({1, s + v});
}
return true;
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, k, b;
cin >> n >> k >> b;
vector<pair<int,int>> edges;
bool ok = true;
if (k % 2) ok = false;
else if (n == 1) {
ok = (k == 0 && b == 0);
} else if (b == n - 2) {
ok = false;
} else if (b == n - 1) {
if (k < 2) ok = false;
else buildTreeCase(n, k, edges);
} else {
if (b > 0 && k == 0) ok = false;
else if (b == 0) {
if (n == 3 && k != 0) ok = false;
else if (n == 3) {
edges.push_back({1, 2});
edges.push_back({2, 3});
edges.push_back({3, 1});
} else {
vector<int> odd;
for (int i = 1; i <= k; i++) odd.push_back(i);
addCore(n, odd, edges);
}
} else {
ok = buildNonTree(n, k, b, edges);
}
}
if (!ok) {
cout << "No\n";
} else {
cout << "Yes\n";
cout << edges.size() << '\n';
for (auto [u, v] : edges) cout << u << ' ' << v << '\n';
}
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
void addCore(int s, const vector<int>& odd, vector<pair<int,int>>& edges) {
vector<pair<int,int>> pairs;
for (int i = 0; i < (int)odd.size(); i += 2) pairs.push_back({odd[i], odd[i + 1]});
vector<int> order;
if (pairs.empty()) {
for (int i = 1; i <= s; i++) order.push_back(i);
} else if ((int)pairs.size() == 1) {
int a = pairs[0].first, b = pairs[0].second;
vector<int> other;
for (int i = 1; i <= s; i++) if (i != a && i != b) other.push_back(i);
order = {a, other[0], b, other[1]};
for (int i = 2; i < (int)other.size(); i++) order.push_back(other[i]);
} else {
vector<int> used(s + 1, 0);
for (auto [a, b] : pairs) {
order.push_back(a);
used[a] = used[b] = 1;
}
for (auto [a, b] : pairs) order.push_back(b);
for (int i = 1; i <= s; i++) if (!used[i]) order.push_back(i);
}
for (int i = 0; i < s; i++) edges.push_back({order[i], order[(i + 1) % s]});
for (auto e : pairs) edges.push_back(e);
}
void buildTreeCase(int n, int k, vector<pair<int,int>>& edges) {
int leaves = k - 2;
int s = n - leaves;
for (int i = 1; i < s; i++) edges.push_back({i, i + 1});
int attach = (s >= 3 ? 2 : 1);
for (int v = s + 1; v <= n; v++) edges.push_back({attach, v});
}
vector<pair<int,int>> buildBlockTree(int b, int d, int x) {
vector<int> deg(b + 1);
deg[0] = d;
for (int i = 1; i <= b; i++) deg[i] = (i <= x ? 1 : 2);
deg[1] += x - d;
vector<int> cur = deg, prufer;
priority_queue<int, vector<int>, greater<int>> leaves;
for (int i = 0; i <= b; i++) {
for (int j = 0; j < deg[i] - 1; j++) prufer.push_back(i);
if (deg[i] == 1) leaves.push(i);
}
vector<pair<int,int>> res;
for (int v : prufer) {
int leaf = leaves.top();
leaves.pop();
res.push_back({leaf, v});
cur[leaf]--;
if (--cur[v] == 1) leaves.push(v);
}
int a = leaves.top(); leaves.pop();
int c = leaves.top(); leaves.pop();
res.push_back({a, c});
return res;
}
bool buildNonTree(int n, int k, int b, vector<pair<int,int>>& edges) {
int s = n - b;
int d = -1, q = -1;
for (int cand = 1; cand <= b && d == -1; cand++) {
if (s == 3) {
for (int qq = 0; qq <= 3; qq++) {
int x = k - qq;
if (x < cand || x > b) continue;
if ((x & 1) != (cand & 1)) continue;
if ((qq & 1) != (cand & 1)) continue;
if (qq != 0 && qq > cand) continue;
d = cand;
q = qq;
break;
}
} else {
int lo = max(0, k - b);
int hi = min(s, k - cand);
if (lo > hi) continue;
int qq = lo;
if ((qq & 1) != (cand & 1)) qq++;
if (qq <= hi) {
d = cand;
q = qq;
}
}
}
if (d == -1) return false;
int x = k - q;
auto blockEdges = buildBlockTree(b, d, x);
vector<int> coreNeighbors;
for (auto [a, c] : blockEdges) {
if (a == 0 || c == 0) coreNeighbors.push_back(a ^ c);
else edges.push_back({s + a, s + c});
}
if (s == 3) {
edges.push_back({1, 2});
edges.push_back({2, 3});
edges.push_back({3, 1});
for (int i = 0; i < (int)coreNeighbors.size(); i++) {
int endpoint = (i < q ? i + 1 : 1);
edges.push_back({endpoint, s + coreNeighbors[i]});
}
} else {
vector<int> want(s + 1, 0);
for (int i = 1; i <= q; i++) want[i] = 1;
if (d & 1) want[1] ^= 1;
vector<int> odd;
for (int i = 1; i <= s; i++) if (want[i]) odd.push_back(i);
addCore(s, odd, edges);
for (int v : coreNeighbors) edges.push_back({1, s + v});
}
return true;
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, k, b;
cin >> n >> k >> b;
vector<pair<int,int>> edges;
bool ok = true;
if (k % 2) ok = false;
else if (n == 1) {
ok = (k == 0 && b == 0);
} else if (b == n - 2) {
ok = false;
} else if (b == n - 1) {
if (k < 2) ok = false;
else buildTreeCase(n, k, edges);
} else {
if (b > 0 && k == 0) ok = false;
else if (b == 0) {
if (n == 3 && k != 0) ok = false;
else if (n == 3) {
edges.push_back({1, 2});
edges.push_back({2, 3});
edges.push_back({3, 1});
} else {
vector<int> odd;
for (int i = 1; i <= k; i++) odd.push_back(i);
addCore(n, odd, edges);
}
} else {
ok = buildNonTree(n, k, b, edges);
}
}
if (!ok) {
cout << "No\n";
} else {
cout << "Yes\n";
cout << edges.size() << '\n';
for (auto [u, v] : edges) cout << u << ' ' << v << '\n';
}
}
}