Codeforces Gym 100975B
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=415185
题目大意:
给出一个n*n的01矩阵,求把它的“1”部分分为两份,使一份经旋转和平移后能够与另一半重合。
分析:
第二次犯错了……Cable TV network……
我们对于第一个点“1”,枚举它在另一个子图中的对应点,再枚举每次旋转的角度,然后对于其他点,逐个枚举它们属于哪一个子图,算出它与基准点的坐标差后再在另一个子图中检查是否有对应点。
我又多枚举一重啊……原本我枚举了两个基准点,完全没必要啊……
正解是枚举平移的坐标差和旋转方向……
哈但我常数巨小,跑得比正解快了4倍多。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)
using namespace std;
const int maxn=20+3,F[4]={0,3,2,1};
int n,size,a[maxn][maxn];
char s[maxn];
bool mark[maxn][maxn],vis[maxn][maxn];
vector<pair<int,int> > v;
void direct(int x,int y,int disx,int disy,int &targetx,int &targety,int d) //计算在旋转d的情况,原基准点(x,y),坐标差disx,disy下,在另一子图中的对应点
{
if (d==0) targetx=x+disx,targety=y+disy;
if (d==1) targetx=x+disy,targety=y-disx;
if (d==2) targetx=x-disx,targety=y-disy;
if (d==3) targetx=x-disy,targety=y+disx;
}
bool check(int p,int q,int d)
{
int px=v[p].first,py=v[p].second;
int qx=v[q].first,qy=v[q].second;
int disx,disy,targetx,targety;
memset(mark,0,sizeof(mark));
memset(vis,0,sizeof(vis));
vis[px][py]=1,vis[qx][qy]=1;
rep(i,0,size-1)
{
if (vis[v[i].first][v[i].second]) continue; //找过了
disx=v[i].first-px,disy=v[i].second-py;
direct(qx,qy,disx,disy,targetx,targety,d);
if ((targetx>=0)&&(targetx<=n)&&(targety>=0)&&(targety<=n)&&(!vis[targetx][targety])&&(a[targetx][targety]))
{vis[targetx][targety]=1;vis[v[i].first][v[i].second]=1;mark[v[i].first][v[i].second]=1;continue;} //匹配成功
disx=v[i].first-qx,disy=v[i].second-qy;
direct(px,py,disx,disy,targetx,targety,F[d]);
if ((targetx>=0)&&(targetx<=n)&&(targety>=0)&&(targety<=n)&&(!vis[targetx][targety])&&(a[targetx][targety]))
{vis[targetx][targety]=1;vis[v[i].first][v[i].second]=1;mark[targetx][targety]=1;continue;}
return false;
}
printf("YES\n");
mark[px][py]=1;
rep(i,1,n)
{
rep(j,1,n)
if (mark[i][j]) printf("%d",1); else printf("%d",0);
printf("\n");
}
return true;
}
int main()
{
freopen("divide.in","r",stdin);
freopen("divide.out","w",stdout);
scanf("%d",&n);
rep(i,1,n)
{
scanf("%s",s+1);
rep(j,1,n)
{
a[i][j]=(s[j]=='0')?0:1;
if (a[i][j]) v.push_back(make_pair(i,j));
}
}
size=(int)(v.size());
if (size==0)
{
printf("YES\n");
rep(i,1,n)
{
rep(j,1,n) printf("%d",0);
printf("\n");
}
return 0;
}
if (size&1) {printf("NO\n");return 0;}
rep(j,1,size-1) //枚举配对点
rep(k,0,3) //枚举方向
if (check(0,j,k)) return 0;
printf("NO\n");
return 0;
}

浙公网安备 33010602011771号