File size: 10,617 Bytes
1fd0050 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | #include <bits/stdc++.h>
using namespace std;
// This is a heuristic construction that tries to realize all edges using a 1D word S,
// and then replicates S on all rows so vertical adjacencies are same-color only.
// It builds S by creating, for each connected component, an Eulerian-like trail on the
// "edge graph" (edges are nodes; adjacency if they share an endpoint). If components > 1,
// it separates them by long runs of the same vertex and attempts to avoid cross-component
// non-edges by ensuring boundaries are equal colors (same-color adjacency).
// If it cannot, it falls back to a trivial K=N map with constant rows (may be invalid for some graphs).
static vector<vector<int>> create_map(int N, int M, vector<int> A, vector<int> B) {
vector<vector<int>> adj(N+1);
vector<int> deg(N+1, 0);
for (int i = 0; i < M; ++i) {
adj[A[i]].push_back(B[i]);
adj[B[i]].push_back(A[i]);
deg[A[i]]++; deg[B[i]]++;
}
// Build components
vector<int> comp_id(N+1, -1);
int compcnt = 0;
for (int u = 1; u <= N; ++u) if (comp_id[u] == -1) {
queue<int> q;
comp_id[u] = compcnt;
q.push(u);
while(!q.empty()){
int x = q.front(); q.pop();
for(int v: adj[x]){
if(comp_id[v]==-1){
comp_id[v]=compcnt;
q.push(v);
}
}
}
compcnt++;
}
// For each component, build a sequence over its vertices whose adjacent distinct pairs
// are exactly the edges in that component. We attempt to create a trail over edges.
// We use Hierholzer-like traversal on the vertex graph to get an Euler trail by doubling edges if needed.
// To ensure existence, we duplicate edges to make all degrees even (construct multigraph with each edge twice),
// then Euler cycle exists in each connected component with at least one edge. From the Euler cycle sequence of vertices,
// adjacent pairs are edges of the multigraph, i.e., original edges, no non-edges.
// For isolated vertices (deg=0), just a single occurrence of that vertex in its own component.
vector<vector<int>> comp_vertices(compcnt);
for(int u=1; u<=N; ++u) comp_vertices[comp_id[u]].push_back(u);
vector<vector<int>> sequences; // one sequence per component
for(int c=0; c<compcnt; ++c){
// collect edges in this component
vector<pair<int,int>> edges;
unordered_map<long long,int> mult; // count occurrences
auto key = [&](int x,int y)->long long{
if(x>y) swap(x,y);
return (long long)x<<20 | y;
};
for(int u: comp_vertices[c]){
for(int v: adj[u]){
if(u < v && comp_id[v]==c){
edges.emplace_back(u,v);
mult[key(u,v)] = 2; // duplicate edge to make degrees even
}
}
}
if(edges.empty()){
// isolated vertices in this component (there may be multiple). Build sequence listing them with repeats to avoid cross pairs.
// Single vertex per component suffice.
sequences.push_back({comp_vertices[c][0]});
continue;
}
// Build multigraph adjacency with duplicated edges
unordered_map<long long,int> rem = mult;
unordered_map<int, vector<int>> g;
for(auto &e: edges){
int u=e.first,v=e.second;
g[u].push_back(v);
g[u].push_back(v);
g[v].push_back(u);
g[v].push_back(u);
}
// Hierholzer
vector<int> seq;
// find starting vertex with non-zero degree
int start = edges[0].first;
// iterative stack
unordered_map<long long,int> used; used.reserve(rem.size()*2);
vector<int> st; st.push_back(start);
vector<int> path;
// For adjacency iteration, we need to remove used edges counts; we'll use rem map.
while(!st.empty()){
int v = st.back();
// find neighbor with remaining edge
bool advanced=false;
auto &nbrs = g[v];
while(!nbrs.empty()){
int u = nbrs.back(); nbrs.pop_back();
long long k = key(v,u);
auto it = rem.find(k);
if(it!=rem.end() && it->second>0){
it->second--;
st.push_back(u);
advanced=true;
break;
}
}
if(!advanced){
path.push_back(v);
st.pop_back();
}
}
if(path.size()<2){
sequences.push_back({start});
}else{
// path is Eulerian circuit; convert to sequence of vertices
reverse(path.begin(), path.end());
// path vertices; adjacent distinct pairs are edges
sequences.push_back(path);
}
}
// Build global sequence S by concatenating component sequences with separators of repeated last symbol to avoid cross-component non-edges.
// We will put between components a very long run of the last symbol of previous, then same symbol again (no change), and then we need to switch to the first of next component.
// This creates a boundary pair (prev_last, next_first). To avoid non-edge at the boundary, we force prev_last == next_first by rotating the next sequence if possible.
// For components with at least one edge (sequence length >=2), we can rotate cycle to start at any vertex; for paths, we can choose start equal to some vertex; but not guaranteed to match previous.
// As a heuristic, we try to reorder components and rotate their sequences to make boundaries either same vertex or an existing edge; if not possible, we will fall back.
// Preprocess: For sequences length >=2 (Eulerian), it's a cycle (first == last). We can rotate freely without changing set of adjacent pairs.
// For sequences length ==1, it's an isolated vertex.
int C = sequences.size();
vector<int> usedComp(C,0);
vector<int> order;
// Greedy: start with a component having length>=2 if exists
int startComp = 0;
for(int i=0;i<C;i++){
if((int)sequences[i].size()>=2){ startComp=i; break; }
}
// simple order as is
for(int i=0;i<C;i++) order.push_back(i);
// Try to rotate to align boundaries
auto rotate_to_start = [&](vector<int> &vec, int val)->bool{
int n=vec.size();
for(int i=0;i<n;i++){
if(vec[i]==val){
rotate(vec.begin(), vec.begin()+i, vec.end());
return true;
}
}
return false;
};
vector<int> S;
bool ok = true;
for(int idx=0; idx<C; ++idx){
int ci = order[idx];
auto seq = sequences[ci];
if(S.empty()){
// Append seq
for(int x: seq) S.push_back(x);
}else{
int prev = S.back();
// Try to rotate seq so that first equals prev (safe boundary)
bool aligned=false;
if(seq.size()>=2){
// For Eulerian cycle, ensure it's cyclic: first == last; our constructed path might have first==last. If not, we can make it cyclic by appending first at end if edge exists? We'll keep as is.
// Try to find prev in seq and rotate.
if(rotate_to_start(seq, prev)){
aligned=true;
}
}else{
// single vertex
if(seq[0]==prev) aligned=true;
}
if(!aligned){
// Try if (prev, seq[0]) is an existing edge; if yes, boundary is valid
bool isEdge=false;
for(int v: adj[prev]) if(v==seq[0]) { isEdge=true; break; }
if(!isEdge){
ok=false;
break;
}
}
// Append with no separator
for(int x: seq) S.push_back(x);
}
}
if(!ok){
// Fallback: trivial N x N constant rows (may be invalid, but we must return something)
int K = max(1, N);
vector<vector<int>> Cmap(K, vector<int>(K, 1));
for(int i=0;i<K;i++){
for(int j=0;j<K;j++){
Cmap[i][j] = i%N + 1;
}
}
return Cmap;
}
// Ensure all colors appear at least once; if not, append them with runs that do not create new adjacencies:
vector<int> seen(N+1,0);
for(int x: S) seen[x]=1;
for(int c=1;c<=N;c++){
if(!seen[c]){
// Append c with a preceding same c to avoid boundary pair, then a same c after.
// Boundary between S.back() and c: to avoid non-edge, if S.back()==c it's fine; else check if (S.back(), c) is an edge; if not, we cannot append safely.
if(!S.empty()){
int prev=S.back();
if(prev!=c){
bool isEdge=false;
for(int v: adj[prev]) if(v==c){ isEdge=true; break; }
if(!isEdge){
// Insert c earlier not possible; give up to fallback
int K = max(1, N);
vector<vector<int>> Cmap(K, vector<int>(K, 1));
for(int i=0;i<K;i++){
for(int j=0;j<K;j++){
Cmap[i][j] = i%N + 1;
}
}
return Cmap;
}
}
}
S.push_back(c);
}
}
int K = (int)S.size();
if(K>240) K = min(240, K);
// Build KxK grid: all rows equal to S[0..K-1], truncated/padded
vector<vector<int>> Cmap(K, vector<int>(K, S[0]));
for(int i=0;i<K;i++){
for(int j=0;j<K;j++){
Cmap[i][j] = S[j%S.size()];
}
}
return Cmap;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
if(!(cin>>T)) return 0;
while(T--){
int N,M; cin>>N>>M;
vector<int> A(M), B(M);
for(int i=0;i<M;i++){ cin>>A[i]>>B[i]; }
auto C = create_map(N,M,A,B);
int P = (int)C.size();
cout<<P<<"\n";
for(int i=0;i<P;i++){
cout<<C[i].size()<<(i+1==P?'\n':' ');
}
for(int i=0;i<P;i++){
for(int j=0;j<(int)C[i].size();j++){
if(j) cout<<" ";
cout<<C[i][j];
}
cout<<"\n";
}
}
return 0;
} |