test 五彩斑斓 (拓扑序+建图)

test 五彩斑斓 (拓扑序+建图)_第1张图片

test 五彩斑斓 (拓扑序+建图)_第2张图片


题解:建图+拓扑序

这道题刚开始想的是乱搞和贪心。就是最后一次粉刷的行或列一定是颜色相同的,满足这个条件的一定是最后一次粉刷,然后将这次操作撤销,再寻找某行或某列全部是同种颜色(或被覆盖的),然后重复次过程。但是这样做存在反例: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  
#include  
#include  
#include  
#include  
#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<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<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<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



你可能感兴趣的:(图论)