【校内模拟】送分题(构造)

mac2024-05-16  31

简要题意:

你有一张无向图,每个节点有颜色,每一轮变换中你需要为每一个点决定它在下一轮的颜色,可选颜色集合为它的颜色和它的所有邻居在这一轮中的颜色。

你需要用不超过20000轮操作来将100个节点的图的颜色从初始状态变为目标状态。

题解:

发现变换操作实际上非常强大,猜想对于一个连通块,只要初始颜色集合把目标态颜色集合包含了就不会有问题。

然后先找路径暴力调整颜色数,然后找路径暴力调整颜色位置。

由于路径长度最多是 O ( n ) O(n) O(n)的,这个做法的调整次数最坏不超过 2 n 2 2n^2 2n2


代码:

#include<bits/stdc++.h> #define ll long long #define re register #define cs const using std::cerr; using std::cout; cs int N=1e2+7,M=2e4+7; int n,m,k; int st[N],col[N],ed[N]; std::vector<int> G[N]; struct node{int t,u,v;}; //t=0 swap(col[u],col[v]) else col[u]=col[v] std::vector<node> vec; std::vector<int> nd; int c1[N],c2[N]; int vis[N],h[N],id[N]; void dfs1(int u){ nd.push_back(u);vis[u]=true;++c1[st[u]],++c2[ed[u]]; for(int re v:G[u])if(!vis[v])dfs1(v); } bool dfs2(int u,int aim,int fa){ if(u==aim)return true;h[u]=true; for(int re v:G[u])if(!h[v]&&dfs2(v,aim,u)){ if(fa==-1)vec.push_back({1,u,v}),col[u]=col[v]; else vec.push_back({0,u,v}),std::swap(col[u],col[v]); return true; }return false; } bool dfs3(int u,int aim,int lim){ if(u==aim)return true;h[u]=true; for(int v:G[u])if(!h[v]&&id[v]<=lim&&dfs3(v,aim,lim)){ std::swap(col[u],col[v]),vec.push_back({0,u,v}); return true; }return false; } void solve(){ while(true){ bool ok=false; for(int u:nd) if(c1[col[u]]>c2[col[u]]){ ok=true; for(int v:nd) if(c1[col[v]]<c2[col[v]]){ c1[col[u]]--,c1[col[v]]++; memset(h,0,n<<2); dfs2(u,v,-1);break; } break; } if(!ok)break; } for(int re i=0;i<nd.size();++i)id[nd[i]]=i; for(int re i=nd.size()-1;~i;--i) if(col[nd[i]]!=ed[nd[i]]){ for(int re j=0;j<i;++j) if(col[nd[j]]==ed[nd[i]]){ memset(h,0,n<<2); dfs3(nd[i],nd[j],i); break; } } } signed main(){ #ifdef zxyoi freopen("hard.in","r",stdin); #endif scanf("%d%d%d",&n,&m,&k); for(int re i=0;i<n;++i)scanf("%d",st+i); for(int re i=0;i<n;++i)scanf("%d",ed+i); for(int re i=1;i<=m;++i){ int u,v;scanf("%d%d",&u,&v);--u,--v; G[u].push_back(v); G[v].push_back(u); }memcpy(col,st,n<<2); for(int re i=0;i<n;++i)if(!vis[i]){ memset(c1,0,k<<2); memset(c2,0,k<<2); nd.clear();dfs1(i); for(int re j=0;j<k;++j)if(c2[j]&&!c1[j]) puts("Impossible"),exit(0);solve(); } for(int re i=0;i<n;++i)cout<<st[i]<<" ";cout<<"\n"; for(auto &t:vec){ if(t.t)st[t.u]=st[t.v]; else std::swap(st[t.u],st[t.v]); for(int re i=0;i<n;++i)cout<<st[i]<<" ";cout<<"\n"; } return 0; }
最新回复(0)