EOJ:Painting
Painting
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submits: 195 | Accepted: 27 |
Description
Ethan wants to draw a painting on an m×n board. He can draw some strips on the board using a paintbrush of width one. In each step, he must choose a new color and paint a full column or a full row.
He has a great image to be drawn on the board, but he doesn’t know which color to use first. You must help him in finding out the order of colors.
Input
There are multiple test cases in the input. The first line of each test case contains two integers m and n, the size of the board (0< m, n <100). Following the first line, there are m lines with n integers denoting the color in each cell. All the colors are positive integer numbers less than 10000. The input is terminated with a single line containing two consecutive zeros.
Output
For each test case, write a single line containing the order of colors used to paint the board. If there are several answers, output the one which is lexicographically smallest (considering each number as a symbol).
Sample Input
4 4
1 5 4 3
6 5 6 6
2 2 2 2
1 5 4 3
3 2
1 1
2 3
2 3
0 0
Sample Output
1 3 4 6 5 2
2 3 1原题地址:http://www.cn210.com/onlinejudge/problemshow.php?pro_id=216
__________________________________________________________________________________________________
题解:
拓扑排序的思想
我的做法:拓扑排序,若行或列中有一个数字出现两次或以上,那么它肯定是最先涂的,这行或列的其他数字肯定是盖在它之上的,由此可以建立有向图。
但是有特殊情况,如:
1 2 3 4
5 5 5 5
6 6 6 6
1,2,3,4这四个数字都只出现了一次,如何判断它是横着刷的还是竖着刷的?其实根据上面的方法,肯定可以发现第二行和第三行已经刷了,而第一列,第二列,第三列,第四列还没刷,所以1,2,3,4只可能是按列刷的。即:若一个数字只出现一次,那么判断除它所在行的其他行有没有已经被刷过,若没有则它是按列刷的,若有,再判断除它所在列的其他列。
但实际上有更快更方便的方法:
暴搜,找行(列)中的同一种颜色出现次数+该行(列)中已经除掉的格子数=列(行)数的颜色,把这种颜色加入答案中,然后在各行各列中把这种颜色除掉。
这是照着标程改的程序,非常精妙。
由于一种颜色要么是在行刷的,要么就是在列刷的,所以只要在读入的时候记录下这个颜色一共出现的次数就行了,标程在读入的时候就确定了这种颜色是在行刷的,还是在列刷的。
代码
1 #include<stdio.h>
2 #include<memory.h>
3 struct point
4 {
5 int x,y,sum,dir;
6 }p[10001];
7 int i,j,m,n,loc,t,flag[201],x[101],y[101],pic[101][101],ans[201];
8 void solve()
9 {
10 memset(p,0,sizeof(p));
11 for (i=1;i<=m;i++)
12 for (j=1;j<=n;j++)
13 {
14 scanf("%d",&pic[i][j]);
15 p[pic[i][j]].sum++;
16 if (p[pic[i][j]].sum==1)
17 {
18 p[pic[i][j]].x=i;
19 p[pic[i][j]].y=j;
20 p[pic[i][j]].dir=0;//这种颜色只出现了一次
21 }
22 else
23 if (p[pic[i][j]].x==i)
24 p[pic[i][j]].dir=1;//在行刷的
25 else p[pic[i][j]].dir=2;//在列刷的
26 }
27 t=0;
28 for (i=1;i<=10000;i++)
29 if (p[i].sum>0)
30 {
31 p[++t].sum=p[i].sum;
32 p[t].x=p[i].x;
33 p[t].y=p[i].y;
34 p[t].dir=p[i].dir;
35 }
36 memset(flag,0,sizeof(flag));
37 memset(x,0,sizeof(x));
38 memset(y,0,sizeof(y));
39 for (i=1;i<=t;i++)
40 {
41 for (j=t;j>=1;j--)
42 {
43 loc=0;
44 if (flag[j]==0&&(p[j].dir==1||p[j].dir==0)&&p[j].sum+x[p[j].x]==n)
45 {
46 loc=j;
47 break;
48 }
49 if (flag[j]==0&&(p[j].dir==2||p[j].dir==0)&&p[j].sum+y[p[j].y]==m)
50 {
51 loc=j;
52 break;
53 }
54 }
55 ans[i]=pic[p[loc].x][p[loc].y];
56 flag[loc]=1;
57 if (p[loc].dir==1||p[loc].dir==0)//更新去除的数。
58 {
59 x[p[loc].x]+=p[loc].sum;
60 for (j=1;j<=n;j++)
61 if (pic[p[loc].x][j]==pic[p[loc].x][p[loc].y])
62 y[j]++;
63 }
64 if (p[loc].dir==2)
65 {
66 y[p[loc].y]+=p[loc].sum;
67 for (j=1;j<=m;j++)
68 if (pic[j][p[loc].y]==pic[p[loc].x][p[loc].y])
69 x[j]++;
70 }
71 }
72 }
73 int main()
74 {
75 scanf("%d%d",&m,&n);
76 while (m!=0)
77 {
78 solve();
79 for (i=t;i>1;i--)
80 printf("%d ",ans[i]);
81 printf("%d\n",ans[i]);
82 scanf("%d%d",&m,&n);;
83 }
84 return 0;
85 }
86