USACO4.4 Frame Up【拓扑排序】

题意居然还读了好久...

读完题目之后大概就知道拓扑排序了。用拓扑可以求出一些字母之间的关系,谁先,谁后。但是这个关系不是唯一确定的,所以就会产生多种方案(题目还要求按字典序输出所有的方案)

输出方案要麻烦一些,最刚开始还没有想到。可以用一个$dfs$,当这个点的入度变为$0$之后,就输出,递归到下一层,然后再回溯。按字母的字典序枚举就可以输出按字典序排的方案。

  1 /*
  2 ID: Starry21
  3 LANG: C++
  4 TASK: frameup         
  5 */
  6 #include<cstdio>
  7 #include<algorithm>
  8 #include<vector>
  9 #include<cstring>
 10 #include<queue>
 11 #include<map>
 12 #include<iostream>
 13 using namespace std;
 14 #define ll long long
 15 #define INF 0x3f3f3f3f
 16 #define N 35
 17 int h,w,n/*一共n个图像(字母)*/;
 18 char mp[N][N];//存图 
 19 int s[N],x[N],z[N],y[N];//每个字母边框的上下左右边在哪一行(列) 
 20 char kd[N];//存字母(1~n) 
 21 bool vis[N];//各种标记 看地方 
 22 
 23 vector<int>G[N];//拓扑的边 
 24 int ind[N];//入度 
 25 char ans[N];
 26 void dfs(int k)
 27 {
 28     //printf("%d
",k);
 29     if(k>n)
 30     {
 31         for(int i=1;i<=n;i++)
 32             printf("%c",ans[i]);
 33         puts("");
 34         return ;
 35     }
 36     for(int i=1;i<=n;i++)
 37         if(ind[kd[i]-'A']==0&&!vis[i])
 38         {
 39             vis[i]=1;
 40             ans[k]=kd[i];
 41             for(int j=0;j<G[kd[i]-'A'].size();j++)
 42             {
 43                 int v=G[kd[i]-'A'][j];
 44                 ind[v]--;
 45             }
 46             dfs(k+1);
 47             vis[i]=0;
 48             for(int j=0;j<G[kd[i]-'A'].size();j++)
 49             {
 50                 int v=G[kd[i]-'A'][j];
 51                 ind[v]++;
 52             }
 53         }
 54 }
 55 int main() 
 56 {
 57     //freopen("frameup.in","r",stdin);
 58     //freopen("frameup.out","w",stdout);
 59     scanf("%d %d",&h,&w);
 60     for(int i=1;i<=h;i++)
 61     {
 62         scanf("%s",mp[i]+1);
 63         for(int j=1;j<=w;j++)
 64         {
 65             if(mp[i][j]=='.') continue;
 66             if(!vis[mp[i][j]-'A'])
 67             {
 68                 kd[++n]=mp[i][j];
 69                 vis[mp[i][j]-'A']=1;
 70             }
 71             if(!s[mp[i][j]-'A']) s[mp[i][j]-'A']=i;
 72             if(!z[mp[i][j]-'A']) z[mp[i][j]-'A']=j;
 73             if(!x[mp[i][j]-'A']) x[mp[i][j]-'A']=i;
 74             if(!y[mp[i][j]-'A']) y[mp[i][j]-'A']=j;
 75             s[mp[i][j]-'A']=min(s[mp[i][j]-'A'],i);
 76             z[mp[i][j]-'A']=min(z[mp[i][j]-'A'],j);
 77             x[mp[i][j]-'A']=max(x[mp[i][j]-'A'],i);
 78             y[mp[i][j]-'A']=max(y[mp[i][j]-'A'],j);
 79             /*
 80             题目保证方块的每一条边都有露出来的
 81             所以直接取min/max就好 
 82             */
 83         }
 84     }
 85     /*for(int i=1;i<=n;i++)
 86     {
 87         printf("%c
",kd[i]);
 88         int id=kd[i]-'A';
 89         printf("%d %d %d %d
",s[id],x[id],z[id],y[id]);
 90     }*/
 91     memset(ind,-1,sizeof(ind));//排除无关字母 
 92     for(int i=1;i<=n;i++)
 93         ind[kd[i]-'A']=0;
 94     for(int i=1;i<=n;i++)//枚举字母
 95     {
 96         memset(vis,0,sizeof(vis));//清空 标记这个点连了哪些 不连重边 
 97         int id=kd[i]-'A';
 98         for(int j=z[id];j<=y[id];j++)
 99             if(mp[s[id]][j]!=kd[i]&&!vis[mp[s[id]][j]-'A'])
100             {
101                 G[id].push_back(mp[s[id]][j]-'A');
102                 vis[mp[s[id]][j]-'A']=1;
103                 ind[mp[s[id]][j]-'A']++;
104             }
105         for(int j=z[id];j<=y[id];j++)
106             if(mp[x[id]][j]!=kd[i]&&!vis[mp[x[id]][j]-'A'])
107             {
108                 G[id].push_back(mp[x[id]][j]-'A');
109                 vis[mp[x[id]][j]-'A']=1;
110                 ind[mp[x[id]][j]-'A']++;
111             }
112         for(int j=s[id];j<=x[id];j++)
113             if(mp[j][z[id]]!=kd[i]&&!vis[mp[j][z[id]]-'A'])
114             {
115                 G[id].push_back(mp[j][z[id]]-'A');
116                 vis[mp[j][z[id]]-'A']=1;
117                 ind[mp[j][z[id]]-'A']++;
118             }
119         for(int j=s[id];j<=x[id];j++)
120             if(mp[j][y[id]]!=kd[i]&&!vis[mp[j][y[id]]-'A'])
121             {
122                 G[id].push_back(mp[j][y[id]]-'A');
123                 vis[mp[j][y[id]]-'A']=1;
124                 ind[mp[j][y[id]]-'A']++;
125             }
126     }
127     sort(kd+1,kd+n+1);
128     memset(vis,0,sizeof(vis));
129     dfs(1);//按照拓扑排序 入度为0之后可以选也可以不选 题目保证有解 
130     return 0;
131 }
Code
原文地址:https://www.cnblogs.com/lyttt/p/11846554.html