题目如下:
#include <iostream>
#include <map>
#include <algorithm>
#include <string.h>
#include <stack>
using namespace std;
const int N=(1<<16)+10;
const int INF = 999999999;
int arr[110]; //记录输入
int dp[110][N];//状态转移,dp[i][j]表示在第i个数状态为j的时候的最小差,这里的状态是用位表示的,比如说出现过4,那么4的因子是2,则第二位的bit变为1,之后在看后一个数和之前的状态是否满足gcd为1的条件时,只要看该数的因子位是否已经为1
int f[110][N];//用来记录第i位第j个状态有没有被访问过
int sol[110][N];//记录到达当前状态选用的数
int trans[110][N];//记录转移到当前状态的前一个状态
int n;
int p[16] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
int getx[60];
void init()
{
for(int k=1;k<60;k++)
{
int ans = 0;
int x = k;
for(int i=0;i<16;i++)
{
if(x%p[i]==0)
{
ans |= (1<<i);
while(x%p[i]==0)
x/=p[i];
}
}
getx[k]=ans;
}
}
int main()
{
init();
while(cin>>n)
{
for(int i=1;i<=n;i++)
cin>>arr[i];
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));
f[0][0] = 1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<60;j++)
{
for(int k=0;k<N;k++)
{
if(f[i-1][k]&&(k&getx[j])==0)
{
int u = k|getx[j];
if(!f[i][u])
{
dp[i][u] = dp[i-1][k]+abs(arr[i]-j);
trans[i][u] = k;
sol[i][u] = j;
}
else if((dp[i-1][k]+abs(arr[i]-j))<dp[i][u])
{
dp[i][u] = dp[i-1][k]+abs(arr[i]-j);
trans[i][u] = k;
sol[i][u] = j;
}
f[i][u]=1;
}
}
}
}
int ans = INF;
int pos = 0;
for(int i=0;i<N;i++)
{
if(f[n][i]&&dp[n][i]<ans)
{
ans = dp[n][i];
pos = i;
}
}
stack<int> ou;
for(int i=n;i>=1;i--)
{
ou.push(sol[i][pos]);
pos = trans[i][pos];
}
while(!ou.empty())
{
cout<<ou.top()<<" ";
ou.pop();
}
cout<<endl;
}
return 0;
}