pku_1128_Frame Stacking

来源:互联网 发布:java异或 编辑:程序博客网 时间:2024/06/05 06:23

这题在次证明了我的英语水平是多么烂~~

题意:

给一些用A-Z组成的窗框,它们相互覆盖,要求自下往上顺序输出覆盖顺序,如果有多种情况按字母顺序排序输出.

这题数据挺水的~理论上有些数据基本过不了~例如26字母的全排序:

1518AAABBBCCCDDDEEEFFFA.AB.BC.CD.DE.EF.FAAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLG.GH.HI.IJ.JK.KL.LGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRM.MN.NO.OP.PQ.QR.RMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXS.ST.TU.UV.VW.WX.XSSSTTTUUUVVVWWWXXXYYYZZZ............Y.YZ.Z............YYYZZZ............
26!的全排列复杂度加上排序复杂度~天呢~

有几种情况要注意

1.多组输出,有不确定的情况全部输出,按字典顺序排列.2.图中的的frame均会给出4条边的情况(一个顶点包括2条边),可以推断出frame的长度和位置.

例如这组数据:

98AAAAAAAAABBBBBBAABCCCCBAABC..CBAABC..CBAABC..CBAABCCCCBAABBBBBBAAAAAAAAA
输出是ABC的全排列,而不是: CBA,如果有被包含的框体不算覆盖,08年亚洲赛有一道最简单的题叫 Ugly Windows 求最上面的一个框,我就当按这个算了~读题的问题没办法啊~~~


因为四个边都会露出来,所以不用考虑这样的数据,直接就能求出框体的位置,相对简单很多:

98AAAAAAAAAB....BAABCCCCBAABC..CBAABC..CBAABC..CBAABCCCCBAABBBBBBAAAAAAAAA

基本解题思想:

这道题是枚举构图+回溯拓扑排序的问题,没有什么变形

首先枚举每个点,求其每个字母的左上和右下的坐标:

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);}//1void 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);}}//2for(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]--;}//3void 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(){//4sort(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();//5vector<int> aa(27);//6dfs(aa,0);//7getResult();}return 0;}


原创粉丝点击