Codeforces gym 100269 I

100 篇文章 0 订阅
5 篇文章 1 订阅

比较恶心的搜索题。
首先翻转操作至多用一次,且只有用和不用的区别,于是可以枚举是否使用。可以发现行和列的排列是无关的,且分别有 6 4 6^4 64种。而数字的交换相当于允许任意排列,可以考虑最小表示法。
这样一个算法就很明显了,我们直接对于每个数独,枚举它是否进行翻转操作,以及行和列的排列,最后求出得到的新数独的最小表示尝试匹配。
但是这样复杂度有点高。由于操作是可逆的,容易发现可以用meet in middle来优化,对于一个数独我们枚举它是否进行翻转以及行的排列,得到一个中间状态,对于另一个数独我们枚举它做列的排列,尝试匹配。
这里需要输出方案,可以考虑记录每个状态所用的排列。
使用哈希的话,时间复杂度为 O ( n ⋅ 9 2 ⋅ 6 4 ) \mathcal O(n\cdot 9^2\cdot 6^4) O(n9264)

#include <bits/stdc++.h>
#define FR first
#define SE second

using namespace std;

typedef long long ll;
typedef pair<int,int> pr;

mt19937 rnd(19260817);

inline int getrnd() {
  return abs((ll)rnd())%(1<<20);
}

const int perm[6][3]={
{1,2,3},
{1,3,2},
{2,3,1},
{2,1,3},
{3,1,2},
{3,2,1}
};

int p[1500][10],bel[1500][4],sz;
int w[81][10];

void pre() {
  for(int t1=0;t1<6;t1++)
  for(int t2=0;t2<6;t2++)
  for(int t3=0;t3<6;t3++)
  for(int t4=0;t4<6;t4++) {
  	sz++;
  	bel[sz][0]=t1;
  	bel[sz][1]=t2;
  	bel[sz][2]=t3;
  	bel[sz][3]=t4;
  	p[sz][1]=(perm[t1][0]-1)*3+perm[t2][0];
  	p[sz][2]=(perm[t1][0]-1)*3+perm[t2][1];
  	p[sz][3]=(perm[t1][0]-1)*3+perm[t2][2];
  	p[sz][4]=(perm[t1][1]-1)*3+perm[t3][0];
  	p[sz][5]=(perm[t1][1]-1)*3+perm[t3][1];
  	p[sz][6]=(perm[t1][1]-1)*3+perm[t3][2];
  	p[sz][7]=(perm[t1][2]-1)*3+perm[t4][0];
  	p[sz][8]=(perm[t1][2]-1)*3+perm[t4][1];
  	p[sz][9]=(perm[t1][2]-1)*3+perm[t4][2];
  }
  for(int i=0;i<81;i++)
    for(int j=0;j<10;j++) w[i][j]=getrnd();
}

struct State {

vector<int> vt;
int id,p,kind,val[10];

State() {}

};

State a[1000005];

namespace Hash {

int head[1<<20],tot;
int num[1000005],nxt[1000005];

void insert(int x) {
  int v=0;
  for(int i=0;i<81;i++) v^=w[i][a[x].vt[i]];
  num[++tot]=x;
  nxt[tot]=head[v];
  head[v]=tot;
}

}

char str[25][11][11];

void search(int n) {
  int tot=0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=sz;j++) {
    	int vis[10],cnt;
    	
    	memset(vis,0,sizeof(vis));
    	a[++tot].id=i;
    	a[tot].p=j;
    	a[tot].kind=0;
    	cnt=0;
    	for(int k=1;k<=9;k++)
    	  for(int l=1;l<=9;l++) {
    	  	char v=str[i][p[j][k]][l];
    	  	if (v=='.') a[tot].vt.push_back(0);
    	  	else {
    	  		v-='0';
    	  		if (!vis[v]) vis[v]=++cnt;
    	  		a[tot].vt.push_back(vis[v]);
			  }
		  }
		for(int k=1;k<=9;k++) {
			if (!vis[k]) vis[k]=++cnt;
			a[tot].val[k]=vis[k];
		}
		Hash::insert(tot);
		
    	memset(vis,0,sizeof(vis));
    	a[++tot].id=i;
    	a[tot].p=j;
    	a[tot].kind=1;
    	cnt=0;
    	for(int k=1;k<=9;k++)
    	  for(int l=1;l<=9;l++) {
    	  	char v=str[i][l][p[j][k]];
    	  	if (v=='.') a[tot].vt.push_back(0);
    	  	else {
    	  		v-='0';
    	  		if (!vis[v]) vis[v]=++cnt;
    	  		a[tot].vt.push_back(vis[v]);
			  }
		  }
		for(int k=1;k<=9;k++) {
			if (!vis[k]) vis[k]=++cnt;
			a[tot].val[k]=vis[k];
		}
		Hash::insert(tot);
		
	    memset(vis,0,sizeof(vis));
    	a[++tot].id=i;
    	a[tot].p=j;
    	a[tot].kind=2;
    	cnt=0;
    	for(int k=1;k<=9;k++)
    	  for(int l=1;l<=9;l++) {
    	  	char v=str[i][k][p[j][l]];
    	  	if (v=='.') a[tot].vt.push_back(0);
    	  	else {
    	  		v-='0';
    	  		if (!vis[v]) vis[v]=++cnt;
    	  		a[tot].vt.push_back(vis[v]);
			  }
		  }
		for(int k=1;k<=9;k++) {
			if (!vis[k]) vis[k]=++cnt;
			a[tot].val[k]=vis[k];
		}
		Hash::insert(tot);
	}
}

pr ans[25][25];
vector <int> vt[25];
int match[25];

void solve(int n) {
  for(int i=0;i<(1<<20);i++)
    if (Hash::head[i]) {
    	int st=0;
    	for(int j=1;j<=n;j++) vt[j].clear();
		for(int j=Hash::head[i];j;j=Hash::nxt[j])
          if (a[Hash::num[j]].kind==2) {
          	int x=a[Hash::num[j]].id;
          	vt[x].push_back(Hash::num[j]);
          	st|=(1<<x);
		  }
		for(int j=Hash::head[i];j;j=Hash::nxt[j])
		  if (a[Hash::num[j]].kind<2) {
		  	int x=a[Hash::num[j]].id;
		  	for(int k=x+1;k<=n;k++)
		  	  if (!((match[x]>>k)&1)&&((st>>k)&1)) {
		  	  	  for(int l=0;l<vt[k].size();l++)
		  	  	    if (a[Hash::num[j]].vt==a[vt[k][l]].vt) {
		  	  	    	  match[x]|=(1<<k);
		  	  	    	  ans[x][k]=pr(Hash::num[j],vt[k][l]);
		  	  	    	  break;
						}
				}
		  } 
	} 
}

vector<pr> query(int x) {
  vector<pr> vt;
  if (x==1) vt.push_back(pr(2,3));
  else if (x==2) {
  	vt.push_back(pr(1,2));
  	vt.push_back(pr(2,3));
  }
  else if (x==3) vt.push_back(pr(1,2));
  else if (x==4) {
  	vt.push_back(pr(1,2));
  	vt.push_back(pr(1,3));
  }
  else if (x==5) vt.push_back(pr(1,3));
  return vt;
}

struct Ope {
  char ch;
  int x,y;
  Ope(char a,int b,int c):ch(a),x(b),y(c) {}
};

void output(int x,int y) {
  int u=ans[x][y].FR,v=ans[x][y].SE;
  if (!u) {
  	puts("No");
  	return;
  }
  vector<pr> cur;
  bool vis[10];
  
  vector<Ope> vt1;
  cur=query(bel[a[u].p][0]);
  for(int i=0;i<cur.size();i++) vt1.push_back(Ope('R',cur[i].FR,cur[i].SE));
  cur=query(bel[a[u].p][1]);
  for(int i=0;i<cur.size();i++) vt1.push_back(Ope('r',cur[i].FR,cur[i].SE));
  cur=query(bel[a[u].p][2]);
  for(int i=0;i<cur.size();i++) vt1.push_back(Ope('r',cur[i].FR+3,cur[i].SE+3));
  cur=query(bel[a[u].p][3]);
  for(int i=0;i<cur.size();i++) vt1.push_back(Ope('r',cur[i].FR+6,cur[i].SE+6));
  memset(vis,0,sizeof(vis));
  for(int i=1;i<=9;i++)
    if (!vis[i]) {
    	int x=i;
    	do {
			vis[x]=1;
    		if (!vis[a[u].val[x]]) vt1.push_back(Ope('D',i,a[u].val[x]));
			x=a[u].val[x]; 
		} while (!vis[x]);
	}
  vector<Ope> vt2;
  cur=query(bel[a[v].p][0]);
  for(int i=0;i<cur.size();i++) vt2.push_back(Ope('C',cur[i].FR,cur[i].SE));
  cur=query(bel[a[v].p][1]);
  for(int i=0;i<cur.size();i++) vt2.push_back(Ope('c',cur[i].FR,cur[i].SE));
  cur=query(bel[a[v].p][2]);
  for(int i=0;i<cur.size();i++) vt2.push_back(Ope('c',cur[i].FR+3,cur[i].SE+3));
  cur=query(bel[a[v].p][3]);
  for(int i=0;i<cur.size();i++) vt2.push_back(Ope('c',cur[i].FR+6,cur[i].SE+6));
  memset(vis,0,sizeof(vis));
  for(int i=1;i<=9;i++)
    if (!vis[i]) {
    	int x=i;
    	do {
			vis[x]=1;
    		if (!vis[a[v].val[x]]) vt2.push_back(Ope('D',i,a[v].val[x]));
			x=a[v].val[x]; 
		} while (!vis[x]);
	}

  int s=vt1.size()+vt2.size()+(a[u].kind==1);
  puts("Yes");
  printf("%d\n",s);
  if (a[u].kind==1) puts("F");
  for(int i=0;i<vt1.size();i++) printf("%c %d %d\n",vt1[i].ch,vt1[i].x,vt1[i].y);
  for(int i=vt2.size()-1;i>=0;i--) printf("%c %d %d\n",vt2[i].ch,vt2[i].x,vt2[i].y);
}

int main() {
  freopen("intellectual.in","r",stdin);
  freopen("intellectual.out","w",stdout);
  pre();
  int n;
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    for(int j=1;j<=9;j++) scanf("%s",str[i][j]+1);
  search(n);
  solve(n);
  for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
      output(i,j);
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。GymCodeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值