这是一个非黑即白的世界。
想必各位都看过题目了,首先翻译下题意:
给一幅无向图,你可以对其每个点染色,要求白黑必须挨着,灰色必须和黑白挨着,问能否染色以及染色方案。
我们可以考虑到,灰色点必然可以被黑白交替的模式代替,所以我们只要黑白染色就好,灰色可以请出去了。怎么染色?要把每个点都要染到?还要交替染?
我们立即想到一个点的入度越少越好,因为这样一个点对于其周围点的影响最小。入度最小?如果图连通,我们可以把它降为1——$\color{red}\sf\large\text{生成树}$恰好满足这一性质。
图不连通呢?
题上可是说了,如果不能成功染色,那么输出NIE
退出就好,另外我们可以想到,联通的图一定是可以完成染色的,所以可以大胆输出TAK
那么!我们再回头看一眼题目,就是这样的:
给一幅无向图,找出里面的生成树,对其上的每个点黑白交替染色,问图是否连通,若连通则输出每个点的颜色(有SPJ)
是否很明了了?献上一份代码(附简注),此处我用的是常规存图+dfs染色。
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
| #include <bits/stdc++.h> #define ri register int #define ll long long using namespace std; int read() { int num=0; int flg=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') { flg=-1; } c=getchar(); } while(isdigit(c)) { num=(num<<1)+(num<<3)+(c^48); c=getchar(); } return num*flg; } const int maxn=1e6+7; struct edge { int to; int nex; } e[maxn];
int cnt=0; int head[maxn]; void add(int u,int v) { e[++cnt].to=v; e[cnt].nex=head[u]; head[u]=cnt; }
bool col[maxn];
bool vis[maxn];
void dfs(int nd,bool cur)
{ vis[nd]=true; col[nd]=cur; for(ri i=head[nd]; i; i=e[i].nex) { int to=e[i].to; if(!vis[to]) { dfs(to,!cur); } } }
int main() { int n=read(); int m=read(); for(ri i=1; i<=m; i++) { int u=read(); int v=read(); vis[u]=vis[v]=true; add(u,v); add(v,u); } for(ri i=1; i<=n; i++) { if(!vis[i]) { return 0&(int)printf("NIE"); } } puts("TAK"); fill(vis+1,vis+n+1,0); for(ri i=1; i<=n; i++) { if(!vis[i]) { dfs(i,0); } } for(ri i=1; i<=n; i++) { if(col[i]==0) { puts("K"); } else { puts("S"); } } }
|
回顾一下:这道题我们首先排除掉了不可能存在的情况
,或者说存在了亦可以被代替的情况(因为SPJ
);随后我们找到了树上染色
是最优的情况,解决问题。