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; 
}
posted @ 2016-07-12 09:06  Krew  阅读(143)  评论(0)    收藏  举报