【校内模拟】五彩斑斓(拓扑排序)

题解:

今天最难的题???

根据抽屉原理,必然有至少一个行或者列是根本没有动过的。

枚举这个行和列,则这一行或列上所有点的颜色来源就是另一个方向。

以此类推,我们可以确定所有行列的染色情况,注意到染色被覆盖是一个先后关系,判断合法可以直接拓扑排序,然后就没了。。。


代码:

#include
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int N=107;

int n,m,tot;
int col[N][N],d[N];
std::vector<int> G[N];
inline void adde(int u,int v){
	G[u].push_back(v);++d[v];
}

int c[N],ban[N],q[N],qn;
int ans_siz,ans_id[N],ans_c[N];

inline bool top_sort(){
	qn=0;for(int re i=1;i<=tot;++i)if(!d[i])q[++qn]=i;
	for(int re i=1;i<=qn;++i)
	{int u=q[i];for(int re v:G[u])if(!--d[v])q[++qn]=v;}
	return qn==tot;
}

inline void update(int id){
	if(!top_sort())return ;int siz=0;
	for(int re i=1;i<=tot;++i)if(c[i]&&c[i]!=-1)++siz;
	if(siz>=ans_siz)return ;int tp=0;cerr<<"update : "<<id<<"\n";
	for(int re i=1;i<=qn;++i)if(c[q[i]]&&c[q[i]]!=-1)ans_id[++tp]=q[i],ans_c[tp]=c[q[i]];
	assert(tp==siz);ans_siz=tp;
}

inline void init(){
	for(int re i=1;i<=tot;++i)G[i].clear(),c[i]=-1,d[i]=0;
}

inline void check_row(int x){init();
	for(int re j=n+1;j<=tot;++j)c[j]=col[x][j];
	for(int re i=1;i<=n;++i)if(i!=x){
		for(int re j=n+1;j<=tot;++j)
		if(c[j]!=col[i][j]){
			if(!col[i][j]||(col[i][j]!=c[i]&&c[i]!=-1))return ;
			c[i]=col[i][j];adde(j,i);
		}
		for(int re j=n+1;j<=tot;++j)
		if(c[i]!=c[j]&&c[j]==col[i][j])adde(i,j);
	}
	for(int re i=1;i<=tot;++i)if(ban[i]&&c[i]!=-1&&c[i]!=0)return ;
	update(x);
}

inline void check_col(int y){init();
	for(int re i=1;i<=n;++i)c[i]=col[i][y];
	for(int re j=n+1;j<=tot;++j)if(j!=y){
		for(int re i=1;i<=n;++i)
		if(c[i]!=col[i][j]){
			if(!col[i][j]||(col[i][j]!=c[j]&&c[j]!=-1))return ;
			c[j]=col[i][j],adde(i,j);
		}
		for(int re i=1;i<=n;++i)
		if(c[j]!=c[i]&&c[i]==col[i][j])adde(j,i);
	}
	for(int re i=1;i<=tot;++i)if(ban[i]&&c[i]!=-1&&c[i]!=0)return ;
	update(y);
}

signed main(){
#ifdef zxyoi
	freopen("iridescent.in","r",stdin);
//	freopen("iridescent.out","w",stdout);
#endif	
	int c;
	scanf("%d%d%d",&n,&m,&c);ans_siz=1e9;tot=n+m;
	for(int re i=1;i<=n;++i)
	for(int re j=n+1;j<=tot;++j)scanf("%d",col[i]+j);
	for(int re i=1;i<=n;++i)
	for(int re j=n+1;j<=tot;++j)ban[i]|=!col[i][j],ban[j]|=!col[i][j];
	for(int re i=1;i<=n;++i)check_row(i);
	for(int re j=n+1;j<=tot;++j)check_col(j);
	if(ans_siz>n+m)puts("-1"),exit(0);
	cout<<ans_siz<<"\n";
	for(int re i=1;i<=ans_siz;++i){
		if(ans_id[i]>n)cout<<"C ",ans_id[i]-=n;
		else cout<<"R ";
		cout<<ans_id[i]<<" "<<ans_c[i]<<"\n";
	}
	return 0;
}

你可能感兴趣的:(拓扑排序,校内模拟)