题解:P14900 [ICPC 2018 Yokohama R] Four-Coloring
ini2015_____ · · 题解
太困难了,zfr 做了好久都不会,由此钦定这个题是上位黑题。
首先发现对于一个
不难发现无论我们怎么删,整张图必然存在一个度数
证毕。 ::::
考虑怎么处理四度点。我们记四个颜色分别是
如果
- 钦定一个颜色
c ,选择一个相邻节点u ,满足u 的颜色c'\ne c 。 - 把所有与
u 相邻的颜色为c 的节点染成c' 。 - 递归下去,直到所有节点的颜色都不与相邻节点相同。
- 如果此时与
v 相邻的节点颜色还是1,2,3,4 ,那么重新选择一个c,u ,否则直接染一个没被占据的颜色
然后这个东西看上去没什么正确性,我们给一个证明。
::::info[证明]
考虑加入我选择节点
考虑互换颜色实际上等于存在一条路径
如果我每次操作都会进行一次颜色的互换,那么等价于对于与
考虑两条路径,如果没有公共的起点 / 终点,那么路径上的颜色不一样,必定不交。
假如存在这样的路径,那么我们对于
这个题有一个很聪明的做法,我们按照 priority_queue。
const int N=1e4+5,inf=1e9+7;
int n,m,T;
vector<int> to[N];
int id[N];
void add(int a,int b){to[a].pb(b),to[b].pb(a);}
bool vis[N];
int col[N],x[N],y[N];
bool cmp(int a,int b){
if(x[a]==x[b])return y[a]<y[b];
return x[a]<x[b];
}
bool cnt[5];
void modify(int u,int x,int y){
col[u]=x;
for(int v:to[u])if(vis[v])if(col[v]==x)modify(v,y,x);
}
int getc(int u){
memset(cnt,0,sizeof cnt);
for(int v:to[u])if(vis[v])cnt[col[v]]=1;
for(int i=1;i<=4;i++)if(!cnt[i])return i;
return 0;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1;i<=n;i++)
id[i]=i;
for(int i=1;i<=m;i++)
add(read(),read());
sort(id+1,id+1+n,cmp);
for(int i=1;i<=n;i++){
int u=id[i];
col[u]=getc(u);
if(!col[u])for(int v:to[u])if(vis[v]){
for(int c=1;c<=4;c++)if(c!=col[v]){
modify(v,c,col[v]);
col[u]=getc(u);
if(col[u])break;
}
if(col[u])break;
}
vis[u]=1;
}
for(int i=1;i<=n;i++)printf("%d\n",col[i]);
return 0;
}
// Think twice,code once