这题在次证明了我的英语水平是多么烂~~
题意:
给一些用A-Z组成的窗框,它们相互覆盖,要求自下往上顺序输出覆盖顺序,如果有多种情况按字母顺序排序输出.
这题数据挺水的~理论上有些数据基本过不了~例如26字母的全排序:
15 18 AAABBBCCCDDDEEEFFF A.AB.BC.CD.DE.EF.F AAABBBCCCDDDEEEFFF GGGHHHIIIJJJKKKLLL G.GH.HI.IJ.JK.KL.L GGGHHHIIIJJJKKKLLL MMMNNNOOOPPPQQQRRR M.MN.NO.OP.PQ.QR.R MMMNNNOOOPPPQQQRRR SSSTTTUUUVVVWWWXXX S.ST.TU.UV.VW.WX.X SSSTTTUUUVVVWWWXXX YYYZZZ............ Y.YZ.Z............ YYYZZZ............26!的全排列复杂度加上排序复杂度~天呢~
有几种情况要注意
1.多组输出,有不确定的情况全部输出,按字典顺序排列. 2.图中的的frame均会给出4条边的情况(一个顶点包括2条边),可以推断出frame的长度和位置.
例如这组数据:
9
8
AAAAAAAA
ABBBBBBA
ABCCCCBA
ABC..CBA
ABC..CBA
ABC..CBA
ABCCCCBA
ABBBBBBA
AAAAAAAA
输出是ABC的全排列,而不是: CBA,如果有被包含的框体不算覆盖,08年亚洲赛有一道最简单的题叫
Ugly Windows 求最上面的一个框,我就当按这个算了~读题的问题没办法啊~~~
因为四个边都会露出来,所以不用考虑这样的数据,直接就能求出框体的位置,相对简单很多:
9
8
AAAAAAAA
AB....BA
ABCCCCBA
ABC..CBA
ABC..CBA
ABC..CBA
ABCCCCBA
ABBBBBBA
AAAAAAAA
基本解题思想:
这道题是枚举构图+回溯拓扑排序的问题,没有什么变形
首先枚举每个点,求其每个字母的左上和右下的坐标:
inline void setPoint(int i,int j)
{
int s=a[i][j]-'A';
disp[s].num++;
disp[s].x1=min(disp[s].x1,i);
disp[s].y1=min(disp[s].y1,j);
disp[s].x2=max(disp[s].x2,i);
disp[s].y2=max(disp[s].y2,j);
}
//fun:init()
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
if(a[i][j]=='.')
continue;
setPoint(i,j);
}
}
根据坐标构图: 若字母X的FRAME存在对字母X检索边框,若该边框位置被字母N覆盖,这产生一条边N->X,并且X的入度加一.:
void setGraphC(int x1,int x2,int y,int x)
{
//检索横边
char s='A'+x;
for(int i=x1;i<=x2;++i) {
int t=a[i][y]-'A';
if(!_hash[t]&&a[i][y]!='.'&&a[i][y]!=s) {
_hash[t]=true;
graph[t][x]=1;
dis[x]++;
}
}
}
void setGraphK(int y1,int y2,int xx,int x)
{
//检索竖边
char s='A'+x;
for(int i=y1;i<=y2;++i) {
int t=a[xx][i]-'A';
if(!_hash[t]&&a[xx][i]!='.'&&a[xx][i]!=s) {
_hash[t]=true;
graph[t][x]=1;
dis[x]++;
}
}
}
void setGraph(int x)
{//检索FRAME边框
dis[x]=0;
memset(_hash,0,sizeof(_hash));
int x1=disp[x].x1;
int x2=disp[x].x2;
int y1=disp[x].y1;
int y2=disp[x].y2;
setGraphC(x1,x2,y1,x);
setGraphC(x1,x2,y2,x);
setGraphK(y1,y2,x1,x);
setGraphK(y1,y2,x2,x);
}
for(int i=0;i<26;++i)
if(disp[i].num!=0)
num++,setGraph(i);
构图完成后,就拓扑排序的步骤,进行回溯:
void dfs(vector<int> &aa,int cnt)
{
if(cnt==num) {
va.push_back(aa);//存储搜索到的数据
return ;
}
for(int i=25;i>=0;--i) {
if(dis[i]==-1) continue;
if(dis[i]==0) {//删入度
dis[i]=-1;
for(int j=0;j<26;++j)
if(graph[i][j])
dis[j]--;
aa[cnt]=i; //存储可行点
dfs(aa,cnt+1);//递归回溯
//还原状态
dis[i]=0;
for(int j=0;j<26;++j)
if(graph[i][j])
dis[j]++;
}
}
}
最后进行排序输出.
源代码:
#include <myhead.h>
typedef struct _point
{
int x1,y1;
int x2,y2;
int num;
}Point; //存储坐标
const int N=33;
int n,m,num; //长宽,用到的字符个数
bool _hash[N];
char a[N][N]; //源数据
int dis[N]; //入度
int graph[N][N];//构图的邻接矩阵
Point disp[N];
vector<vector<int> > va; //存储答案
inline void setPoint(int i,int j)
{
int s=a[i][j]-'A';
disp[s].num++;
disp[s].x1=min(disp[s].x1,i);
disp[s].y1=min(disp[s].y1,j);
disp[s].x2=max(disp[s].x2,i);
disp[s].y2=max(disp[s].y2,j);
}
void setGraphC(int x1,int x2,int y,int x)
{
char s='A'+x;
for(int i=x1;i<=x2;++i) {
int t=a[i][y]-'A';
if(!_hash[t]&&a[i][y]!='.'&&a[i][y]!=s) {
_hash[t]=true;
graph[t][x]=1;
dis[x]++;
}
}
}
void setGraphK(int y1,int y2,int xx,int x)
{
char s='A'+x;
for(int i=y1;i<=y2;++i) {
int t=a[xx][i]-'A';
if(!_hash[t]&&a[xx][i]!='.'&&a[xx][i]!=s) {
_hash[t]=true;
graph[t][x]=1;
dis[x]++;
}
}
}
void setGraph(int x)
{
dis[x]=0;
memset(_hash,0,sizeof(_hash));
int x1=disp[x].x1;
int x2=disp[x].x2;
int y1=disp[x].y1;
int y2=disp[x].y2;
setGraphC(x1,x2,y1,x);
setGraphC(x1,x2,y2,x);
setGraphK(y1,y2,x1,x);
setGraphK(y1,y2,x2,x);
}
//1
void init()
{
num=0;
memset(dis,-1,sizeof(dis));
memset(graph,0,sizeof(graph));
for(int i=0;i<26;++i) {
disp[i].num=0;
disp[i].x1=disp[i].y1=N;
disp[i].x2=disp[i].y2=0;
}
for(int i=0;i<n;++i)
scanf("%s",a[i]);
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j) {
if(a[i][j]=='.')
continue;
setPoint(i,j);
}
}
//2
for(int i=0;i<26;++i)
if(disp[i].num!=0)
num++,setGraph(i);
}
inline void delVetx(int x)
{
for(int i=0;i<26;++i)
if(graph[x][i])
dis[i]--;
}
//3
void dfs(vector<int> &aa,int cnt)
{
if(cnt==num) {
va.push_back(aa);
return ;
}
for(int i=25;i>=0;--i) {
if(dis[i]==-1) continue;
if(dis[i]==0) {
dis[i]=-1;
for(int j=0;j<26;++j)
if(graph[i][j])
dis[j]--;
aa[cnt]=i;
dfs(aa,cnt+1);
dis[i]=0;
for(int j=0;j<26;++j)
if(graph[i][j])
dis[j]++;
}
}
}
bool cmp(vector<int> aa,vector<int> bb)
{// 排序时注意逆向排序,因为要求自底向上输出结果,在这里卡了半小时...手生啦~~~
size_t mm=num-1;
while(aa[mm]==bb[mm]&&mm!=0)
mm--;
return aa[mm]<bb[mm];
}
void getResult()
{
//4
sort(va.begin(),va.end(),cmp);
vector<int> t;
for(size_t i=0;i<va.size();++i) {
t=va[i];
for(int j=num-1;j>=0;j--) {
printf("%c",t[j]+'A');
}
puts("");
t.clear();
}
for(size_t i=0;i<va.size();++i)
va[i].clear();
va.clear();
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
init();
//5
vector<int> aa(27);
//6
dfs(aa,0);
//7
getResult();
}
return 0;
}