2021 ICPC 沈阳 J (bfs)

14 篇文章 0 订阅

题目
题意: 给定四个数0-9的数,变成另外四个0-9的数。每次可以选择1-4个连续的数,都+1或者都-1 (mod 10).
思路: bfs,搜索从0000到其他状态的最短路。然后哩,我们可以发现从状态a转移到b,相当于从0000转移到b-a.相当于有个偏移量,直接到a状态了,搜索b-a需要多少步即可。
没想到可以转化成b-a,蚌埠住了。
合法的状态转移我是用dfs,3^4暴搜搜出来的。
代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e4+10;
int n,m,k,T;
struct node{
	int a[4];
};
int a[4];
int dist[10][10][10][10]; //到某个状态的最短路
int add(int x)
{
	return (x+1)%n;
}
int sub(int x)
{
	return (x-1+n)%n;
}
vector<int> res;
vector<vector<int> > v;
int fa[10];
int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void dfs(int cur)
{
	if(cur==4)
	{
		for(int i=0;i<4;++i) fa[i] = i;
		vector<int> t;
		int flag = 0;
		for(int i=0;i<res.size();++i)
		{
			if(res[i]!=0) 
			{
				if(res[i]==-1) flag |= 1;
				if(res[i]==1) flag |= 2;
				t.push_back(i);
			}
		}
		if(flag==3||flag==0) return ;
		int tot = t.size();
		for(int i=0;i<tot;++i)
		{
			int l = t[i];
			int r = (t[(i+1)%tot]);
			if(l+1==r) ;
			else continue;
			int u = find(l),v = find(r);
			if(u!=v) 
			{
				fa[v] = u;
			}
		}
		int all = 0;
		for(int i=0;i<tot;++i)
		{
			if(find(t[i])==t[i]) all++;
		}
		if(all==1)
		{
			v.push_back(res);	
		} 
		return ;
	}
	res.push_back(1);
	dfs(cur+1);
	res.pop_back();
	res.push_back(-1);
	dfs(cur+1);
	res.pop_back();
	res.push_back(0);
	dfs(cur+1);
	res.pop_back();
}
void bfs(int aa,int bb,int cc,int dd)
{
	memset(dist,0x3f,sizeof(dist));
	queue<node> q;
	q.push({aa,bb,cc,dd});
	dist[aa][bb][cc][dd] = 0;
	int cnt = 0;
	while(q.size())
	{
		node tmp = q.front(); q.pop();
		int va[4];
		int a[4];
		for(int i=0;i<4;++i) 
		{
			a[i] = va[i] = tmp.a[i];
		}
		for(auto &vv:v)
		{
			for(int i=0;i<4;++i)
			{
				va[i] = (a[i]+vv[i]+10)%10;
			}
			if(dist[va[0]][va[1]][va[2]][va[3]] > dist[a[0]][a[1]][a[2]][a[3]] + 1) 
			{
				dist[va[0]][va[1]][va[2]][va[3]] = dist[a[0]][a[1]][a[2]][a[3]] + 1;
				q.push({va[0],va[1],va[2],va[3]});
			}
//			if(va[0]==2&&va[1]==2&&va[2]==8&&va[3]==8)
//			{
//				cout<<dist[va[0]][va[1]][va[2]][va[3]]<<"??\n";
//				for(int i=0;i<4;++i) cout<<a[i]<<" "; cout<<"?\n";
//			}
		}
	}
}
void solve()
{
	node t1,t2;
	for(int i=0;i<4;++i)
	{
		scanf("%1d",&t1.a[i]);
	}
	for(int i=0;i<4;++i)
	{
		scanf("%1d",&t2.a[i]);
		t2.a[i] = (t2.a[i] - t1.a[i] + 10) % 10;
//		cout<<i<<":"<<t2.a[i]<<"\n";
	}
	int ans = dist[t2.a[0]][t2.a[1]][t2.a[2]][t2.a[3]];
	printf("%d\n",ans);
}
signed main(void)
{
	v.push_back({0,0,0,0});
	dfs(0);
//	for(auto &vv:v)
//	{
//		for(auto &item:vv) cout<<item<<" ";
//		cout<<"\n";
//	}
//	n = 10;
	bfs(0,0,0,0);
	scanf("%d",&T);
	while(T--)
	solve();
	return 0;	
} ```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值