题解 P2741 【[USACO4.4]重叠的图像Frame Up】
这道题是我在USACO里面用时最久的一道好了不废话了
这一道题正解是拓扑,但是我觉得拓扑比暴力更好打。。。。
思路:
因为“矩形的每条边中,至少有一部分是可见的”,所以我们只
需要根据边来找出矩形的左上角和右上角
然后搜索每一个矩阵,如果这个矩阵被别的矩阵覆盖了,就与
另外一个矩阵建立一条边,然后拓扑一次就好了
注:没有被连接的矩形才是最底的(当前),这样可以省去很
的步骤
代码如下:
#include<bits/stdc++.h>
#include<cstdlib>
using namespace std;
struct node
{
int x,y,next;
}a[5100];int len,last[51];//边,表示要先用了这一个矩阵才能用下一个矩阵
int s[51];//表示有多少个矩阵在这一个点的上面
struct node1
{
int x1,y1;
int x2,y2;
node1()
{
x1=y1=100;
}
}g[51];//记录左上和右下
inline void ins(int x,int y)//建边
{
len++;
a[len].x=x;a[len].y=y;s[y]++;
a[len].next=last[x];last[x]=len;
}
int n,m,length,d[51];//length表示出现的矩阵的次数,d为编目录优化,这个还挺有用的
int f[51][51];//地图
bool v[51];//这种型号的矩阵是否有
inline void find(int k)//查找为k的矩阵
{
bool bk[51];memset(bk,true,sizeof(bk));//记录那种矩形是否被找过,如果找过了,就没有必要多建边了
for(int j=g[k].y1;j<=g[k].y2;j++)//先找上下
{
if(f[g[k].x1][j]!=k && bk[f[g[k].x1][j]]==true)
{
ins(k,f[g[k].x1][j]);
bk[f[g[k].x1][j]]=false;
}
if(f[g[k].x2][j]!=k && bk[f[g[k].x2][j]]==true)
{
ins(k,f[g[k].x2][j]);
bk[f[g[k].x2][j]]=false;
}
}
for(int i=g[k].x1;i<=g[k].x2;i++) //再找左右
{
if(f[i][g[k].y1]!=k && bk[f[i][g[k].y1]]==true)
{
ins(k,f[i][g[k].y1]);
bk[f[i][g[k].y1]]=false;
}
if(f[i][g[k].y2]!=k && bk[f[i][g[k].y2]]==true)
{
ins(k,f[i][g[k].y2]);
bk[f[i][g[k].y2]]=false;
}
}
}
int b[51];//记录拓扑时的队列
inline void tuopu(int x,int t)//删边或者回溯
{
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
s[y]+=t;
}
}
void dfs(int k)//拓扑排序,k表示现在队列里有k-1个
{
if(k==length+1)//如果到达了
{
for(int i=1;i<k;i++) printf("%c",b[i]+'A'-1);//变为字符串然后输出
printf("\n");return;
}
for(int i=1;i<=length;i++)//枚举
{
if(v[d[i]]==true)//如果没有被找过
{
if(s[d[i]]==0)//如果地下没有矩形了
{
v[d[i]]=false;
b[k]=d[i];//记录
tuopu(d[i],-1);//伪删边
dfs(k+1);//往下搜索
v[d[i]]=true;//回溯
b[k]=0;
tuopu(d[i],1);
}
}
}
}
inline int cmp(const void *xx,const void *yy)//排序
{
int x=*(int*)xx;
int y=*(int*)yy;
if(x>y) return 1;
if(x<y) return -1;
return 0;
}
int main()
{
char st[51];int i,j;
scanf("%d%d",&n,&m);
memset(v,false,sizeof(v));
for(i=1;i<=n;i++)
{
scanf("%s",st+1);
for(j=1;j<=m;j++)
{
if(st[j]=='.') continue;//不用管没有的
f[i][j]=st[j]-'A'+1;
if(v[f[i][j]]==false)
{
v[f[i][j]]=true;
length++;d[length]=f[i][j];
}
g[f[i][j]].x1=min(g[f[i][j]].x1,i);//记录左上角和右下角
g[f[i][j]].y1=min(g[f[i][j]].y1,j);
g[f[i][j]].x2=max(g[f[i][j]].x2,i);
g[f[i][j]].y2=max(g[f[i][j]].y2,j);
}
}
qsort(d+1,length,sizeof(int),cmp);//记得排序目录
for(i=1;i<=length;i++)//找一次
{
find(d[i]);
}
dfs(1);//拓扑排序
return 0;
}