10.25
(USACO铜组三题)
我已经发了两题的博客,一题是失去的母牛,另一题是牛的基因组学,现在还有一题现代艺术。
现代艺术
题目描述:
世界各地的艺术评论家直到现在才开始意识到伟大的牛画家Bibi的创意天赋。
Bibi用一种特殊的方式绘画。她用一块N*N的画布开始画画 “0”表示一个画布的空单元格。然后她在画布上画了9个矩形。她会使用9种颜色的一种(为了方便(Bibi是个很懒的人),她把颜色编号为1~9). 她每次可以选择任意一种未使用过的颜色进行绘画。
举个例子,如果她从颜色2开始画,下面是她画画的过程:
2220
2220
2220
0000
然后她可能画了一个颜色为7的矩形:
2220
2777
2777
0000
随后她画了一个颜色为3的小矩形:
2230
2737
2777
0000
每一个矩形的边都是平行于边缘的,鉴于画布的最终状态,请计算出画布上有多少种颜色可能是第一次被画上去的。
(矩形的大小是不确定的 可能是一个单元格 也可能覆盖整个画布)
输入格式(文件名:art.in)
第一行是整数n(1<=n<=10)下面n*n的矩阵由数字0~9组成,描述的是最后完成的画布。
输出格式(文件名 art.out)
输出一个整数 表示最终画布的颜色中,可能为第一个画上去的颜色个数。
样例输入:
4
2230
2737
2777
0000
样例输出:
1
样例解释:在本例中,只有颜色2可能是第一个被绘制的。颜色3显然是在颜色7之后画的,而颜色7显然是在颜色2之后画的。
代码
#include<bits/stdc++.h>
using namespace std;
int n,s=0;
char a[15][15];
string tmp;
bool b[15]={},c[15][15];
int main()
{
freopen("art.in","r",stdin);
freopen("art.out","w",stdout);
scanf("%d",&n);
getline(cin,tmp);
for (int i=1;i<=n;++i)
{
for (int j=1;j<=n;++j)
{
scanf("%c",&a[i][j]);
b[a[i][j]-'0']=true;
}
getline(cin,tmp);
}
for (int i=1;i<=9;++i)
if (b[i])
{
int x=100,y=100,xx=0,yy=0;
for (int j=1;j<=n;++j)
for (int k=1;k<=n;++k)
if (a[j][k]-'0'==i)
{
x=min(x,j);
y=min(y,k);
xx=max(xx,j);
yy=max(yy,k);
}
for (int j=x;j<=xx;++j)
for (int k=y;k<=yy;++k)
if (a[j][k]-'0'!=i)
c[i][a[j][k]-'0']=true;
}
for (int i=1;i<=9;++i)
if (b[i])
{
bool flag=true;
for (int j=1;j<=9;++j)
if (c[j][i]) flag=false;
if (flag) s++;
}
cout<<s<<endl;
return 0;
}
思路
先输入这个方阵,用a二维字符数组存储,然后我用b一维数组来存储哪些颜色出现过。中间的循环是主体,循环的目的是:找到每一个出现过的颜色的最大矩形,然后在这个最大矩形里开始搜索,寻找跟它不同的颜色。这里有一个玄学操作,这是我听了一位神一般的大佬的方法后才AC的。——用一个c二维数组来标记涂颜色的顺序,左端点比右端点先涂标记为真,这样,哪些颜色先涂,哪些颜色后涂就很清楚了。之后的那一个循环,目的是:找到每一个出现过的颜色,如果它比其它颜色后涂,那么它肯定不是第一个涂的颜色,flag标记为假。最后统计flag为真的个数就是可能为第一个涂的颜色的个数。