1. 程式人生 > 實用技巧 >【SSLOJ1460】逛機房

【SSLOJ1460】逛機房

題目

思路

考慮到可以特判 \(n=10^6\),這樣每個數就只有 6 位。可以考慮 bfs。
但是每次詢問都 bfs 一次複雜度顯然不對。發現目標狀態是一樣的,且 \(10^6\) 以內的完全平方數只有 \(10^3\) 個,所以可以從目標狀態開始搜尋,然後 \(O(1)\) 詢問。
那麼每次有兩種轉移方式:

  • 將這個數字任意一位修改成任意一個數(注意不可以將最高位修改為 0)。
  • 將一個位置前的數字全部向前移一位,然後在這個空出來的位置修改成任意數字。

時間複雜度 \(O(n+Q)\)

程式碼

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
using namespace std;

const int N=1000010;
int Q,n,dis[N]; 
bool vis[N];

struct node
{
	int a[7];
};
queue<node> q;

int get(node x)
{
	int s=0;
	for (int i=1;i<=6;i++)
		s=s*10+x.a[i];
	return s;
}

void bfs()
{
	while (q.size())
	{
		node u=q.front();
		q.pop();
		int len=1;
		while (len<6 && !u.a[len]) len++;
		for (int i=1;i<=6;i++)
			for (int j=0;j<=9;j++)
			{
				if (i==len && !j) continue;
				node v=u; v.a[i]=j;
				if (!dis[get(v)])
				{
					dis[get(v)]=dis[get(u)]+1;
					q.push(v);
				}
			}
		if (len==1) continue;
		for (int i=len;i<=6;i++)
		{
			node v=u;
			for (int j=1;j<i;j++)
				v.a[j]=v.a[j+1];
			for (int j=0;j<=9;j++)
			{
				v.a[i]=j;
				if (!dis[get(v)])
				{
					dis[get(v)]=dis[get(u)]+1;
					q.push(v);
				}
			}
		}
	}
}

int main()
{
	for (int i=1;i<1000;i++)
	{
		int p=i*i;
		node a;
		for (int j=6;j>=1;j--)
			a.a[j]=p%10,p/=10;
		q.push(a);
		dis[get(a)]=1;
	}
	bfs();
	scanf("%d",&Q);
	while (Q--)
	{
		scanf("%d",&n);
		if (n==1000000) printf("0\n");
			else printf("%d\n",dis[n]-1);
	}
	return 0;
}