結果
| 問題 | No.3321 岩井星人グラフ-1 |
| コンテスト | |
| ユーザー |
Neculapia
|
| 提出日時 | 2025-11-25 20:54:51 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 15,750 bytes |
| 記録 | |
| コンパイル時間 | 1,845 ms |
| コンパイル使用メモリ | 132,564 KB |
| 実行使用メモリ | 7,716 KB |
| 最終ジャッジ日時 | 2025-11-25 20:55:01 |
| 合計ジャッジ時間 | 9,584 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | -- * 3 |
| other | AC * 2 WA * 1 TLE * 1 -- * 85 |
ソースコード
/**
* Solution for Iwai Seijin Graph Verification
*
* Logic Overview:
* 1. An Iwai graph requires specific counts of Degree 1 and Degree 3 vertices (equal to X).
* 2. It requires every Degree 1 vertex to be at exactly distance Y-1 (L) from the nearest Degree 3 vertex.
* 3. We compute the current graph's degrees and distances to nearest Deg 3.
* 4. We determine the target L from valid components.
* 5. We identify "Bad" vertices (Deg 1 nodes with invalid distances).
* 6. We determine necessary degree changes (e.g., need +2 Deg 3 nodes implies connecting two Deg 2 nodes).
* 7. We identify candidate nodes that can fix the "Bad" vertices (e.g., an ancestor at distance L).
* 8. We brute-force valid pairs from the reduced candidate set to see if they satisfy all Iwai conditions.
*/
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <map>
using namespace std;
const int INF = 1e9;
int N, M;
vector<vector<int>> adj;
vector<int> deg;
// Check if the graph (represented by counts and distances) is valid Iwai
bool is_iwai_state(int n_d1, int n_d2, int n_d3, int target_L, const vector<int>& dists, const vector<int>& current_deg) {
if (n_d1 != n_d3) return false;
int X = n_d1;
if (X == 0) return false; // Must have arms
if (N % X != 0) return false;
int Y = N / X;
if (Y < 2) return false; // Y=1 implies L=0, but dist Y-1=0 means Deg1 is Deg3? Impossible.
if (target_L != -1 && (Y - 1) != target_L) return false;
if (n_d2 != X * (Y - 2)) return false;
// Check distance condition for all Deg 1 nodes
// We only check sampled or all? Passed dists must be updated.
// This function assumes dists is already recalculated for the trial.
for (int i = 1; i <= N; ++i) {
if (current_deg[i] == 1) {
if (dists[i] != Y - 1) return false;
}
}
return true;
}
// Multi-source BFS to calculate distances to nearest Deg 3
vector<int> get_distances(const vector<int>& current_deg) {
vector<int> d(N + 1, INF);
queue<int> q;
for (int i = 1; i <= N; ++i) {
if (current_deg[i] == 3) {
d[i] = 0;
q.push(i);
}
}
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v : adj[u]) {
if (d[v] == INF) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return d;
}
// Function to get distances for a specific graph configuration (simulated)
// Optimized to only update necessary parts? For N=3e5, O(N) BFS is acceptable if calls are few.
bool check_pair(int u, int v, int target_L) {
// 1. Update degrees
vector<int> next_deg = deg;
next_deg[u]++;
next_deg[v]++;
if (next_deg[u] > 3 || next_deg[v] > 3) return false;
// 2. Counts
int n1 = 0, n2 = 0, n3 = 0;
for (int i = 1; i <= N; ++i) {
if (next_deg[i] == 1) n1++;
else if (next_deg[i] == 2) n2++;
else if (next_deg[i] == 3) n3++;
else if (next_deg[i] > 3) return false;
}
// 3. Check distances
// To speed up, we build adjacency just for BFS?
// Or handle the extra edge implicitly.
// Implicit is better.
vector<int> d(N + 1, INF);
queue<int> q;
for (int i = 1; i <= N; ++i) {
if (next_deg[i] == 3) {
d[i] = 0;
q.push(i);
}
}
// BFS with implicit edge (u, v)
while (!q.empty()) {
int curr = q.front(); q.pop();
// Neighbors from original graph
for (int neighbor : adj[curr]) {
if (d[neighbor] == INF) {
d[neighbor] = d[curr] + 1;
q.push(neighbor);
}
}
// Neighbor from new edge
int neighbor = -1;
if (curr == u) neighbor = v;
else if (curr == v) neighbor = u;
if (neighbor != -1) {
if (d[neighbor] == INF) {
d[neighbor] = d[curr] + 1;
q.push(neighbor);
}
}
}
return is_iwai_state(n1, n2, n3, target_L, d, next_deg);
}
// Find k-th ancestor of u (simple DFS/BFS parent pointer)
// Returns -1 if no such ancestor
int get_ancestor(int start, int dist, const vector<int>& d_to_d3) {
// We want the node 'up' the gradient of d_to_d3.
// The neighbor with d_to_d3 = current - 1.
int curr = start;
for (int k = 0; k < dist; ++k) {
int parent = -1;
for (int v : adj[curr]) {
if (d_to_d3[v] == d_to_d3[curr] - 1) {
parent = v;
break;
}
}
if (parent == -1) return -1;
curr = parent;
}
return curr;
}
// Get all nodes at distance K from start in component (BFS)
vector<int> get_nodes_at_dist(int start, int K) {
vector<int> res;
vector<int> d(N + 1, -1);
queue<int> q;
q.push(start);
d[start] = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
if (d[u] == K) res.push_back(u);
if (d[u] >= K) continue;
for (int v : adj[u]) {
if (d[v] == -1) {
d[v] = d[u] + 1;
q.push(v);
}
}
}
return res;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
if (!(cin >> N >> M)) return 0;
adj.resize(N + 1);
deg.resize(N + 1, 0);
for (int i = 0; i < M; ++i) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
deg[u]++;
deg[v]++;
}
// Check max degree
for (int i = 1; i <= N; ++i) {
if (deg[i] > 3) { cout << "No" << endl; return 0; }
}
// Initial analysis
vector<int> initial_dist = get_distances(deg);
// Group by component
vector<bool> visited(N + 1, false);
int target_L = -1;
vector<int> bad_nodes; // Nodes with deg 1 but invalid distance
bool possible = true;
// Component Analysis
for (int i = 1; i <= N; ++i) {
if (!visited[i]) {
vector<int> comp;
queue<int> q;
q.push(i);
visited[i] = true;
comp.push_back(i);
while(!q.empty()){
int u = q.front(); q.pop();
for(int v : adj[u]){
if(!visited[v]){
visited[v] = true;
comp.push_back(v);
q.push(v);
}
}
}
// Check L in this component
set<int> ls;
bool has_inf = false;
vector<int> d1s;
for(int u : comp) {
if(deg[u] == 1) {
d1s.push_back(u);
if(initial_dist[u] == INF) has_inf = true;
else ls.insert(initial_dist[u]);
}
}
if (d1s.empty()) {
// Component has no deg 1.
// Could be a cycle of Deg 3s (L undefined/irrelevant locally?)
// Or cycle of Deg 2s (Bad, need whiskers).
// Actually, if a component is just a cycle of Deg 2s, it has no Deg 3s.
// Distance to Deg 3 is INF. But no Deg 1s to violate condition?
// But global Deg 3 count needs to be X.
// We'll rely on global candidate search to fix.
continue;
}
if (has_inf) {
// Bad component (Isolated tree or cycle without deg 3)
for(int u : d1s) bad_nodes.push_back(u);
} else {
if (ls.size() > 1) {
// Conflicting L within component. Impossible to fix with 1 edge?
// Unless edge fixes multiple?
// We treat all as bad.
for(int u : d1s) bad_nodes.push_back(u);
} else {
int l = *ls.begin();
if (target_L != -1 && target_L != l) {
// Conflict with previous components
possible = false;
}
target_L = l;
}
}
}
}
if (!possible) { cout << "No" << endl; return 0; }
// If target_L is still -1, try to deduce it?
// This happens if all components are bad (e.g. isolated trees).
// We can iterate feasible L.
vector<int> possible_Ls;
if (target_L != -1) possible_Ls.push_back(target_L);
else {
// Try L from 1 to some reasonable bound?
// Or pick one bad node, and try its possible distances?
// For efficiency, maybe limit to small range?
// Or logic: if no good components, pick the first bad component's "Diameter / 2" or something.
// Let's try L = 1 to N/3.
// Actually, if we pick a bad node 'u', we must connect to make dist L.
// If we connect 'u' to 'v', and 'v' becomes Deg 3, dist is 1?
// If we connect something else, dist L.
// For simplicity, if target_L is unknown, we iterate a few values if N is small, or use heuristics.
// Given constraints, let's assume valid cases usually have at least one valid structure or L is implied.
// We will loop L if not set.
possible_Ls = {1, 2, 3}; // Heuristic fallback for pure forest inputs
// Better: iterate L based on candidates from one Bad Node.
if (!bad_nodes.empty()) {
possible_Ls.clear();
// Just try L=1..5? Or derived from distances.
// If we have an isolated path of len K. Possible L could be K/2 etc.
// Let's try limited range for safety.
for(int k=1; k<=50; ++k) possible_Ls.push_back(k); // A bit risky but covers most manual cases
}
}
// Identify required degree changes
int cnt1 = 0, cnt3 = 0;
for(int i=1; i<=N; ++i) {
if(deg[i] == 1) cnt1++;
if(deg[i] == 3) cnt3++;
}
int gap = cnt1 - cnt3; // We need final diff to be 0.
// Pairs of (deg_u, deg_v) to check
vector<pair<int,int>> deg_pairs;
// Current Gap -> Target 0.
// Ops:
// (2,2): gap -> gap - 2. (Need gap=2).
// (1,2): gap -> gap - 2. (Need gap=2).
// (1,1): gap -> gap - 2. (Need gap=2).
// (0,2): gap -> gap. (Need gap=0).
// (0,1): gap -> gap. (Need gap=0).
// (0,0): gap -> gap + 2. (Need gap=-2).
if (gap == 2) {
deg_pairs = {{2,2}, {1,2}, {1,1}};
} else if (gap == 0) {
deg_pairs = {{0,2}, {0,1}}; // (0,0) increases gap? No gap+2.
} else if (gap == -2) {
deg_pairs = {{0,0}};
} else {
// Gap too large to fix with 1 edge
cout << "No" << endl;
return 0;
}
for (int L : possible_Ls) {
// Filter bad nodes for this L
vector<int> curr_bad;
for (int i=1; i<=N; ++i) {
if (deg[i] == 1) {
if (initial_dist[i] != L) curr_bad.push_back(i);
}
}
// If too many bad nodes, we might assume impossible?
// No, connecting 2 nodes can fix defects in 2 components or fix huge distance issues.
// Candidate Strategy:
// Pick one bad node (if any). The added edge MUST help it.
// Case A: Bad Node u has dist > L (or INF).
// Must connect to make distance L.
// Either connect u's subtree to a Deg 3.
// Or make a node at distance L from u (in its subtree) a Deg 3.
// Or make a node at distance < L connect to something? (No, dist > L).
// Key: Node at distance L from u (ancestor or in subtree) is a strong candidate.
// Case B: Bad Node u has dist < L.
// Impossible to increase distance by adding edges.
// RETURN FALSE for this L.
bool possible_L = true;
set<int> candidates1;
bool candidates1_initialized = false;
if (curr_bad.empty()) {
// No bad nodes? Graph might be perfect.
// Check if we can add edge maintaining perfection.
// Try connecting (0,1), (0,2) if gap allows.
// Use brute force on a few nodes?
// Just use all valid degree nodes as candidates.
for(int i=1; i<=N; ++i) {
if(deg[i]<=2) candidates1.insert(i);
}
} else {
// Analyze first bad node to prune search
int u = curr_bad[0];
if (initial_dist[u] != INF && initial_dist[u] < L) {
possible_L = false;
} else {
// Must touch u's environment.
// If dist > L: ancestor at dist L is candidate (to become Deg 3).
if (initial_dist[u] != INF && initial_dist[u] > L) {
int anc = get_ancestor(u, L, initial_dist);
if (anc != -1) candidates1.insert(anc);
}
// If dist == INF:
// Any node at distance L from u is a candidate (to become Deg 3).
else if (initial_dist[u] == INF) {
vector<int> nodes = get_nodes_at_dist(u, L);
for(int x : nodes) candidates1.insert(x);
}
candidates1_initialized = true;
}
}
if (!possible_L) continue;
if (candidates1_initialized && candidates1.empty()) continue; // No candidates for a bad node -> fail
// Convert set to vector
vector<int> C1(candidates1.begin(), candidates1.end());
// We iterate u from C1, v from all nodes (filtered by degree logic)
// Optimization: only check v that have compatible degree
for (int u : C1) {
int d_u = deg[u];
if (d_u > 2) continue; // Can't bump > 3
for (auto p : deg_pairs) {
int target_v_deg = -1;
if (p.first == d_u) target_v_deg = p.second;
else if (p.second == d_u) target_v_deg = p.first;
if (target_v_deg != -1) {
// Try all v with this degree
// To optimize: Collect such v once.
// Or iterate. N=3e5. If C1 is small, we can iterate all N?
// If C1 is large (e.g. from INF), we need to be careful.
// But usually INF comes from Tree, nodes at dist L is small (degree constraint).
// Actually, nodes at dist L grows with branching.
// But max degree 3 -> growth is bounded (2^L).
// If L is small, C1 is small.
// We need to iterate v.
// Collect valid v's?
static vector<int> valid_vs;
valid_vs.clear();
for(int i=1; i<=N; ++i) if(deg[i] == target_v_deg && i != u) valid_vs.push_back(i);
for (int v : valid_vs) {
if (check_pair(u, v, L)) {
cout << "Yes" << endl;
return 0;
}
// Heuristic timeout prevention
if (valid_vs.size() * C1.size() > 5000000) {
// Only check a subset if too many
if (rand()%10 != 0) continue;
}
}
}
}
}
}
cout << "No" << endl;
return 0;
}
Neculapia