题解:建图+拓扑序
这道题刚开始想的是乱搞和贪心。就是最后一次粉刷的行或列一定是颜色相同的,满足这个条件的一定是最后一次粉刷,然后将这次操作撤销,再寻找某行或某列全部是同种颜色(或被覆盖的),然后重复次过程。但是这样做存在反例:4 4 5
1 1 1 1
5 4 5 5
1 1 1 1
5 5 5 5 实际上先染一行5再染一列4,再把那1 3 4三行染上更优,但是上面的做法会把5分成三列染。
有一个重要的特点,就是每行每列至多被染一次,一定存在一行或者一列是没有被染过色的(就是都是染别的间接染上的,颜色不同)。
那么我就可以枚举没被染过色的行(或列,下面都以行为例)。然后其实就得知了每一列染的颜色(与这一行的对应位置颜色相同),然后我们扫描每行看是否有不和谐的格子,就是与当前列颜色不同的格子,需要通过粉刷行来满足,并且粉刷行一定再列之后。如果之前的格子要求此行的颜色与当前要求不同,那么产生冲突意味着无解,否则就从列向行连边。然后还要检查某些位置是否要求列的粉刷在行之前,然后连边。然后可以利用拓扑序得到一组合法的解,拓扑序中的点就是粉刷的方案。如果图中存在环则说明无解。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 53
using namespace std;
int n,m,c,coll[N],colh[N],ins[N*2],v[N*N*2],point[N*2],next[N*N*2],tot,q[N*N];
int col[N][N],que[N*2],size,mark[N*2],ans,pt[N*2];
int col1[N][N],que1[N*2],ans1,mark1[N*2],pt1[N*2];
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; ins[y]++;
//cout<<x<<" "<<y<<endl;
}
bool solve()
{
int head=0; int tail=0;
//for (int i=1;i<=n+m;i++) cout<<ins[i]<<" ";
// cout<<endl;
for (int i=1;i<=n;i++)
if (!ins[i]&&colh[i]&&colh[i]!=-1) q[++tail]=i;
for (int i=n+1;i<=n+m;i++)
if (!ins[i]&&coll[i-n]&&coll[i-n]!=-1) q[++tail]=i;
while (head<tail) {
int now=q[++head];
for (int i=point[now];i;i=next[i])
{
ins[v[i]]--;
if (!ins[v[i]]) q[++tail]=v[i];
}
}
size=tail;
for (int i=1;i<=n+m;i++)
if (ins[i]>0) return false;
return true;
}
bool check(int now)
{
for (int i=1;i<=m;i++) coll[i]=col[now][i];
for (int i=1;i<=n;i++) colh[i]=-1; colh[now]=0;
tot=0;
memset(ins,0,sizeof(ins));
memset(point,0,sizeof(point));
//cout<<endl;
for (int i=1;i<=n;i++)
{
if (now==i) continue;
for (int j=1;j<=m;j++)
if (col[i][j]!=coll[j]) {
if (col[i][j]==0&&coll[j]) return false;
if (colh[i]==-1) colh[i]=col[i][j];
else if (colh[i]!=col[i][j]) return false;
}
if (colh[i]==-1) colh[i]=0;
if (!colh[i]) continue;
for (int j=1;j<=m;j++){
if (coll[j]==0) continue;
if (coll[j]!=col[i][j]) add(j+n,i);
else if (coll[j]==col[i][j]&&colh[i]!=coll[j]) add(i,j+n);
}
}
bool f=solve();
return f;
}
int main()
{
freopen("iridescent.in","r",stdin);
freopen("iridescent.out","w",stdout);
scanf("%d%d%d",&n,&m,&c);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) scanf("%d",&col[i][j]);
ans=n*m; ans1=n*m; bool pd=false;
for (int i=1;i<=n;i++)
if (check(i)&&size<ans) {
ans=size; que[0]=size; pd=true;
for (int j=1;j<=size;j++)
{
if (q[j]>n) mark[j]=1,que[j]=q[j]-n,pt[j]=coll[que[j]];
else que[j]=q[j],mark[j]=0,pt[j]=colh[que[j]];
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) col1[j][i]=col[i][j];
swap(n,m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) col[i][j]=col1[i][j];
/*for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++) cout<<col[i][j]<<" ";
cout<<endl;
} */
for (int i=1;i<=n;i++)
if (check(i)&&size<ans1) {
ans1=size; que1[0]=size; pd=true;
for (int j=1;j<=size;j++)
{
if (q[j]>n) mark1[j]=1,que1[j]=q[j]-n,pt1[j]=coll[que1[j]];
else que1[j]=q[j],mark1[j]=0,pt1[j]=colh[que1[j]];
}
}
if (!pd) {
printf("-1\n");
return 0;
}
if (ans<ans1) {
printf("%d\n",ans);
for (int i=1;i<=ans;i++){
if (mark[i]) printf("C ");
else printf("R ");
printf("%d %d\n",que[i],pt[i]);
}
return 0;
}
printf("%d\n",ans1);
for (int i=1;i<=ans1;i++){
if (mark1[i]) printf("R ");
else printf("C ");
printf("%d %d\n",que1[i],pt1[i]);
}
}