和上一题一样的一个覆盖问题,这个要给出全部可能序列,所以就有个递归过程
用了很多stl,本来以为会TLE,结果0ms就过了,还有很大的优化空间,比如可以把拓扑的dfs和入度为0结合起来就可以少很多重复搜索的情况。
/* author:jxy lang:C/C++ university:China,Xidian University **If you need to reprint,please indicate the source** */ #include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; int h,w,map[32][32],cnt; char ans[100];//暂存排序 vector<int> cover[27];//覆盖关系 vector<string> Ans;//全部排序 int l[27],r[27],u[27],d[27],in[27],k;//最左最右最上最下,和记录是否在排序中 bool init() { int i,j,k; if(scanf("%d%d",&h,&w)!=2)return 0; memset(l,127,sizeof(l));memset(u,127,sizeof(u));//127只是个大数 memset(r,-1,sizeof(r));memset(d,-1,sizeof(d)); Ans.clear();cnt=0; for(i=0;i<27;i++)cover[i].clear(); for(i=0;i<h;i++) { getchar(); for(j=0;j<w;j++) { k=getchar()-'A'; map[i][j]=k; if(k<0)continue; l[k]=min(l[k],j);r[k]=max(r[k],j); u[k]=min(u[k],i);d[k]=max(d[k],i); } } return 1; } bool build()//寻找覆盖关系 { int i,j; for(i=0;i<26;i++) { if(r[i]<0)continue; cnt++; for(j=l[i];j<=r[i];j++) { if(map[u[i]][j]!=i)cover[i].push_back(map[u[i]][j]);//这一步可能重复添加很多次……但是n较少可以接受,最好优化 if(map[d[i]][j]!=i)cover[i].push_back(map[d[i]][j]); } for(j=u[i]+1;j<d[i];j++) { if(map[j][l[i]]!=i)cover[i].push_back(map[j][l[i]]); if(map[j][r[i]]!=i)cover[i].push_back(map[j][r[i]]); } } k=cnt-1;ans[cnt]='\0'; return 1; } bool dfs(int v) { in[v]=1; for(int u,i=0;i<cover[v].size();i++) { u=cover[v][i]; if(!in[u])dfs(u);//因为数据保证,不需判断环 } ans[k--]=v+'A'; return 1; } void check() { int t=k; int a[35]; memcpy(a,in,sizeof(a)); for(int i=0;i<26;i++) { if(r[i]<0||in[i])continue; if(!dfs(i))return; if(k<0)Ans.push_back(ans);//加入,会有重复,可优化 else check(); memcpy(in,a,sizeof(a));//恢复状态 k=t; } } int main() { while(init()) { build(); memset(in,0,sizeof(in)); check(); sort(Ans.begin(),Ans.end());//字典序 int len=unique(Ans.begin(),Ans.end())-Ans.begin();//去重 for(int i=0;i<len;i++) cout<<Ans[i]<<endl; } }
时间: 2024-09-17 02:58:36