最小m段和问题
【问题描述】
给定 n 个整数组成的序列,现在要求将序列分割为 m 段,每段子序列中的数在原序列
中连续排列。如何分割才能使这 m段子序列的和的最大值达到最小?
算法设计:
给定 n 个整数组成的序列,计算该序列的最优 m段分割,使 m段子序列的和的最大值达到最小。
【输入形式】
输入数据:第 1 行中有 2 个正整数 n 和 m。正整数 n 是序列的长度;正整数 m是分割的段数。接下来的一行中有 n 个整数。
【输出形式】
将计算结果输出:第 1 行中的数是计算出的 m段子序列的和的最大值的最小值。
【样例输入】
1 1
10
【样例输出】
10
/*
--------------------------------------
--------------------------------------
------Problem: 8918.最小m段和问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,a[1005];
int dp[1005][1005];
int sum[1005][1005];
int main()
{
cin >> n >> m;
for(int i=1; i<=n; i++) cin >> a[i];
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
dp[i][j] = 1000000000;
for(int i=1; i<=n; i++) {
int num = 0;
for(int j=i; j<=n; j++) {
num += a[j];
sum[i][j] = num;
}
dp[i][1] = sum[1][i];
}
for(int i=2; i<=n; i++) {
for(int j=2; j<=i && j<=m; j++) {
int p;
for(int k=1; k<i; k++)
dp[i][j] = min(dp[i][j], max(dp[k][j - 1], sum[k + 1][i]));
}
}
cout << dp[n][m] << endl;
return 0;
}
最大 k 乘积问题
【问题描述】
设 I 是一个 n 位十进制整数。如果将 I 划分为 k 段,则可得到 k 个整数。这 k 个整数的
乘积称为 I 的一个 k 乘积。试设计一个算法,对于给定的 I 和 k,求出 I 的最大 k 乘积。
算法设计:
对于给定的 I 和 k,计算 I 的最大 k 乘积。
【输入形式】
输入数据:第 1 行中有 2 个正整数 n 和 k。正整数 n 是序列
的长度;正整数 k 是分割的段数。
接下来的一行中是一个 n 位十进制整数。(n<=10)
【输出形式】
将计算结果输出:第 1 行中的数是计算出的最大 k 乘积。
【样例输入】
2 1
15
【样例输出】
15
/*
--------------------------------------
--------------------------------------
-------Problem: 8917.最大k乘积问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
int dp[15][15]; //最大乘积数组
char numstr[15];
int num[15];
int getValue(int i,int j) {
int sum = 0;
for(int k=i; k<j; k++) {
sum += num[k];
sum *= 10;
}
return sum + num[j];
}
void dpAlgo(int l,int k) {
for(int i=1; i<=l; i++)
dp[i][1] = getValue(1,i);
for(int i=0; i<=l; i++) {
for(int j=2; j<=k; j++) {
int temp = 0;
for(int d=1; d<i; d++)
temp = max(temp,dp[d][j-1] * getValue(d+1,i));
dp[i][j] = temp;
}
}
}
int main()
{
int l,k;
cin>>l>>k>>numstr;
for(int i=0; i<l; i++)
num[i+1] = numstr[i] - '0';
dpAlgo(l,k);
cout << dp[l][k];
return 0;
}
石子合并问题
【问题描述】
在一个圆形操场的四周摆放着 n 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将 n 堆石子合并成一堆的最小得分和最大得分。
算法设计:
对于给定 n 堆石子,计算合并成一堆的最小得分和最大得分。
【输入形式】
输入数据:第 1 行是正整数 n,1≤n≤100,表示有 n 堆石子。
第二行有 n 个数,分别表示每堆石子的个数。
【输出形式】
将计算结果输出:第 1 行中的数是最小得分;第 2 行中的数是最大得分。
【样例输入】
4
4 4 5 9
【样例输出】
43
54
/*
--------------------------------------
--------------------------------------
--------Problem: 8920.石子合并问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
const int INF=0x7fffffff;
int n,m,ans1,ans2;
int A[205],f1[205][205],f2[205][205];
int dfs1(int L,int R){
//求出最小得分
if(f1[L][R])return f1[L][R]; //已保存的状态不必搜索
if(L==R) return f1[L][R]=0; //L==R时返回0
int res=INF; //初始值赋为最大值以求最小值
for(int k=L;k<R;k++) //枚举K搜索
res=min(res,dfs1(L,k)+dfs1(k+1,R)+A[R]-A[L-1]);
return f1[L][R]=res; //记录状态
}
int dfs2(int L,int R){
//求出最大得分
if(f2[L][R])return f2[L][R];
if(L==R) return f2[L][R]=0; //若初始值为0可省略该句
int res=0; //初始值设为0
for(int k=L;k<R;k++)
res=max(res,dfs2(L,k)+dfs2(k+1,R)+A[R]-A[L-1]);
return f2[L][R]=res;
}
int main(){
std::ios::sync_with_stdio(false);//取消cin与stdin同步,加速读入
cin>>n;
for(int i=1;i<=n;i++){
cin>>A[i];
A[i+n]=A[i]; //因为是环所以保存为长度为2n的链以保证不会漏解
}
for(int i=1;i<=2*n;i++) //求出前缀和
A[i]+=A[i-1];
dfs1(1,2*n);dfs2(1,2*n); //搜索出1-2n的最大得分与最小得分
ans1=INF; ans2=0;
for(int i=1;i<=n;i++){
ans1=min(f1[i][n+i-1],ans1);//选出答案
ans2=max(f2[i][n+i-1],ans2);
}
cout<<ans1<<"\n"<<ans2;
return 0;
}
最大长方体问题
【问题描述】
一个长,宽,高分别为 m,n,p 的长方体被分割成个 mnp 个小立方体。每个小立方体内有一个整数。试设计一个算法,计算出所给长方体的最大子长方体。子长方体的大小由它所含所有整数之和确定。
算法设计:
对于给定的长,宽,高分别为 m,n,p 的长方体,计算最大子长方体的大小。
【输入形式】
输入数据:第 1 行是 3 个正整数 m,n,p,1≤m,n,p≤50。接下来 m*n 行每行 p 个正整数,表示小立方体中的数。
【输出形式】
将计算结果输出:第 1 行中的数是计算出的最大子长方体的大小。
【样例输入】
3 3 3
0 -1 2
1 2 2
1 1 -2
-2 -1 -1
-3 3 -2
-2 -3 1
-2 3 3
0 1 3
2 1 -3
【样例输出】
14
/*
--------------------------------------
--------------------------------------
-------Problem: 8916.最大长方体问题---
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
int maxsum(int n,int *a)
{
int sum=0,b=0;
for (int i=1; i<=n; i++)
{
if(b>0) b+=a[i];
else b=a[i];
if(b>sum) sum=b;//记录最大值
}
return sum;
}
int maxsum2(int m,int n, int **a){
int sum=0;
int *b=new int [n+1];
for (int i=1; i<=m; i++) {
for(int k=1; k<=n; k++)
b[k]=0;//置0
for(int j=i; j<=m; j++) {
//动规思想,将m分成1~i和i+1~m两段
for (int k=1; k<=n; k++)
b[k] += a[j][k];
int max=maxsum(n,b);
if(max>sum) sum=max;
}
}
return sum;
}
int maxsum3(int m,int n,int p,int ***a)
{
int sum=0;
int **c=new int*[n+1];
for(int i=1; i<=n; i++) c[i]=new int [p+1];
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
for(int k=1; k<=p ; k++) c[j][k]=0;//置0
for (int l=i; l<=m; l++) {
//和二维的思想一样
for(int j=1; j<=n; j++)
for(int k=1; k<=p ; k++) c[j][k]+=a[l][j][k];
int max=maxsum2(n,p,c);
if(max>sum) sum=max;
}
}
return sum;
}
int main()
{
int m,n,p,***a;
cin>>m>>n>>p;
a=new int**[m+1];
for(int i=1; i<=m; i++) a[i]=new int*[n+1]; //一维
for(int i=1; i<=m; i++)
for (int j=1; j<=n; j++)
a[i][j]=new int[p+1]; //二维
for(int i=1; i<=m; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=p; k++)
cin>>a[i][j][k]; //三维
cout<<maxsum3(m,n,p,a);
}
序关系计数问题
【问题描述】
用关系“<”和“=”将 3 个数 A、B 和 C 依序排列时有 13 种不同的序关系:A=B=C,A=B<C,A<B=C,A<B<C,A<C<B,A=C<B,B<A=C,B<A<C,B<C<A,B=C<A,C<A=B,C<A<B,C<B<A。将n 个数(1 ≤ n ≤50)依序排列时有多少种序关系。
算法设计:
计算出将n 个数(1 ≤ n ≤50)依序排列时有多少种序关系。
【输入形式】
输入数据:输入数据有多行,每行提供一个数n 。
【输出形式】
将找到的序关系数输出:一行一个。
【样例输入】
3
5
【样例输出】
13
541
/*
--------------------------------------
--------------------------------------
-------Problem: 8923.序关系计数问题---
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
#define MAX_N 51
using namespace std;
__int64 dp[MAX_N][MAX_N]; //dp[i][j]:i个数,有j个‘<’链接,共有多少种情况
int main()
{
int n,i,j;
for(i=0; i<MAX_N; i++) dp[i][0]=1;
for(i=0; i<MAX_N; i++)
for(j=1; j<i; j++)
dp[i][j] = (j+1)*(dp[i-1][j]+dp[i-1][j-1]);
for(i=0; i<MAX_N; i++)
for(j=0; j<i; j++)
dp[i][i] += dp[i][j]; //dp[i][i]存放每一行的和
while(scanf("%d",&n)==1){
printf("%I64d\n",dp[n][n]);
}
return 0;
}
汽车加油行驶问题
【问题描述】
给定一个N*N 的方形网格,设其左上角为起点,坐标为(1,1),X 轴向右为正,Y 轴向下为正,每个方格边长为1。一辆汽车从起点出发驶向右下角终点,其坐标为(N,N)。在若干个网格交叉点处,设置了油库,可供汽车在行驶途中加油。汽车在行驶过程中应遵守
如下规则:(1)汽车只能沿网格边行驶,装满油后能行驶K 条网格边。出发时汽车已装满油,在起点与终点处不设油库。(2)当汽车行驶经过一条网格边时,若其 X 坐标或 Y 坐标减小,则应付费用B,否则免付费用。(3)汽车在行驶过程中遇油库则应加满油并付加油费用A。(4)在需要时可在网格点处增设油库,并付增设油库费用C(不含加油费用A)。(5)(1)~(4)中的各数N、K、A、B、C均为正整数。
算法设计:
求汽车从起点出发到达终点的一条所付费用最少的行驶路线。
【输入形式】
输入数据:
第一行是N,K,A,B,C的值,2 ≤ N ≤ 100,2 ≤ K ≤ 10。第二行起是一个N*N 的0-1方阵,每行N 个值,至N+1行结束。方阵的第i行第j 列处的值为1 表示在网格交叉点(i,j)处设置了一个油库,为0 时表示未设油库。各行相邻的2 个数以空格分隔。
【输出形式】
将找到的最优行驶路线所需的费用,即最小费用输出:第1行中的数是最小费用值。
【样例输入】
9 3 2 3 6
0 0 0 0 1 0 0 0 0
0 0 0 1 0 1 1 0 0
1 0 1 0 0 0 0 1 0
0 0 0 0 0 1 0 0 1
1 0 0 1 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0 1
1 0 0 1 0 0 0 1 0
0 1 0 0 0 0 0 0 0
【样例输出】
12
/*
--------------------------------------
--------------------------------------
-----Problem: 8910.汽车加油行驶问题---
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include<bits/stdc++.h>
#include<set>
#include<map>
using namespace std;
#define MAX 120
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Line
{
int v,next,w;
}e[MAX*MAX*MAX];
int h[MAX*MAX],cnt=1,tot;
int m[MAX*MAX],g[MAX][MAX],n,K,A,B,C;
bool vis[MAX*MAX][15];
inline void Add(int u,int v,int w)
{
e[cnt]=(Line){
v,h[u],w};h[u]=cnt++;
}
int dis[MAX*MAX][15];
void SPFA()
{
memset(dis,63,sizeof(dis));
dis[g[1][1]][K]=0;
queue<int> Q,Q1;
Q.push(g[1][1]);Q1.push(K);
while(!Q.empty())
{
int u=Q.front(),t=Q1.front();
Q.pop();Q1.pop();
if(t!=0)
{
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v,gg=t-1,Dis=dis[u][t]+e[i].w;
if(m[v])gg=K,Dis+=A;
if(dis[v][gg]>Dis)
{
dis[v][gg]=Dis;
if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
}
}
}
int v=u,gg=K,Dis=dis[u][t]+C+A;
if(dis[v][gg]>Dis)
{
dis[v][gg]=Dis;
if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
}
vis[u][t]=false;
}
}
int main()
{
n=read();K=read();A=read();B=read();C=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
g[i][j]=++tot,m[g[i][j]]=read();;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(i!=n) Add(g[i][j],g[i+1][j],0);
if(j!=n) Add(g[i][j],g[i][j+1],0);
if(i!=1) Add(g[i][j],g[i-1][j],B);
if(j!=1) Add(g[i][j],g[i][j-1],B);
}
SPFA();
int ans=1e9;
for(int i=0;i<=K;++i)ans=min(ans,dis[g[n][n]][i]);
printf("%d\n",ans);
return 0;
}
最少硬币问题
【问题描述】
设有 n 种不同面值的硬币,各硬币的面值存于数组 T[1:n]中。现要用这些面值的硬币来找钱。可以使用的各种面值的硬币个数存于数组 Coins[1:n]中。对任意钱数 0≤m≤20001,设计一个用最少硬币找钱 m 的方法。
算法设计:
对于给定的 1≤n≤10,硬币面值数组 T 和可以使用的各种面值的硬币个数数组 Coins,以及钱数 m,0≤m≤20001,计算找钱 m的最少硬币数。
【输入形式】
输入数据:第一行中只有 1 个整数给出n 的值,第 2 行起每
行 2 个数,分别是 T[j]和 Coins[j]。最后 1 行是要找的钱数 m。
【输出形式】
将计算出的最少硬币数输出。问题无解时输出-1。
【样例输入】
3
1 3
2 3
5 3
18
【样例输出】
5
/*
--------------------------------------
--------------------------------------
--------Problem: 8913.最少硬币问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
/*多重背包(硬币种类有限制,硬币数目有限制)*/
#include <iostream>
using namespace std;
const int maxvalue = 20001;
const int coinnum = 15;
int mymin(int a,int b){
return a < b ? a : b;
}
int main()
{
int n;
cin >> n;
int coin[coinnum];
int coincount[coinnum];
for(int i=0; i<n; i++)
{
cin >> coin[i];
cin >> coincount[i];
}
int m;
cin >> m;
//钱数为dp[i]是的硬币数目
int *dp = new int[maxvalue]();
//重点错误
//for(int i=0; i<=m; i++)是错的
for(int i=1; i<=m; i++) dp[i] = maxvalue;
int i,j,k;
for(i=0; i<n; i++)//硬币面值的种数
{
for(j=1; j<=coincount[i]; j++)//硬币的面值的个数
{
for(k=m; k>=coin[i]; k--) //动态迁移方程为
dp[k] = mymin(dp[k - coin[i]] + 1, dp[k]);
}
}
if(dp[m] == maxvalue)
cout << -1 << endl;
else cout << dp[m] << endl;
return 0;
}
租用游艇问题
【问题描述】
长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站 i 到游艇出租站 j 之间的租金为 r(i,j),1≤i<j≤n。试设计一个算法,计算出从游艇出租站 1 到游艇出租站 n 所需的最少租金。
算法设计:
对于给定的游艇出租站 i 到游艇出租站 j 之间的租金为 r(i,j),1≤i<j≤n,计算从游艇出租站 1 到游艇出租站 n 所需的最少租金。
【输入形式】
输入数据:第 1 行中有 1 个正整数 n(n<=200),表示有 n个游艇出租站。接下来的 n-1 行是 r(i,j),1≤i<j≤n。
【输出形式】
将计算出的从游艇出租站 1 到游艇出租站 n 所需的最少租金输出。
【样例输入】
3
5 15
7
【样例输出】
12
/*
--------------------------------------
--------------------------------------
--------Problem: 8924.租用游艇问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int n,v[222][222];
int dp[222];//dp[i]表示到第i个游艇出租站所需的最少租金
int main()
{
scanf("%d",&n);
for(int i=1; i<n; i++)
for(int j=i+1; j<=n; j++)
scanf("%d",&v[i][j]);
memset(dp,INF,sizeof(dp));
dp[1]=0;
for(int i=2; i<=n; i++)
for(int j=1; j<i; j++)
dp[i] = min(dp[i],dp[j]+v[j][i]);
printf("%d\n",dp[n]);
return 0;
}
红黑树的红色内结点问题
【问题描述】
红黑树是一类特殊的二叉搜索树,其中每个结点被“染成”红色或黑色。若将二叉搜索树结点中的空指针看作是指向一个空结点,则称这类空结点为二叉搜索树的前端结点。并规定所有前端结点的高度为-1。
一棵红黑树是满足下面“红黑性质”染色二叉搜索树:
(1)每个结点被染成红色或黑色;
(2)每个前端结点为黑色结点;
(3)任一红结点的儿子结点均为黑结点;
(4)在从任一结点到其子孙前端结点的所有路径上具有相同的黑结点数。
从红黑树中任一结点 x 出发(不包括结点 x),到达一个前端结点的任意一条路径上的黑结点个数称为结点 x 的黑高度,记作 bh(x)。红黑树的黑高度定义为其根结点的黑高度。图示的二叉搜索树是一棵红黑树。标在结点旁边的数字是相应结点的黑高度。
算法设计:
给定正整数 n,试设计一个算法,计算出在所有含有 n 个结点的红黑树中,红色内结点个数的最小值和最大值。
【输入形式】
输入数据:第一行是正整数 n,1<n<5000。
【输出形式】
将红色内结点个数的最小值和最大值输出:第 1 行是最小值,第 2行是最大值。
【样例输入】
8
【样例输出】
1
4
/*
--------------------------------------
--------------------------------------
------8830. 红黑树的红色内结点问题----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
int n,m,ans;
int main()
{
scanf("%d",&n);
m=n+1;
while(m>1) {
ans+=m&1;m>>=1;
}
printf("%d\n",ans);
m=n+1;ans=0;
while(m>1)
{
if(m==2) ans++;
if((m&3)==1) ans+=m/4*2-1,m/=4,m++;
else if((m&3)==2) ans+=m/4*2,m/=4,m++;
else if((m&3)==3) ans+=m/4*2+1,m/=4,m++;
else ans+=m/4*2,m/=4;
}
printf("%d\n",ans);
return 0;
}
编辑距离问题
【问题描述】
设 A 和 B 是 2 个字符串。要用最少的字符操作将字符串 A 转换为字符串 B。这里所说的字符操作包括
(1)删除一个字符;
(2)插入一个字符;
(3)将一个字符改为另一个字符。
将字符串 A 变换为字符串 B 所用的最少字符操作数称为字符串 A 到 B 的编辑距离,记为d(A,B)。试设计一个有效算法,对任给的2个字符串A和B,计算出它们的编辑距离d(A,B)。
算法设计:
对于给定的字符串 A 和字符串 B,计算其编辑距离 d(A,B)。
【输入形式】
输入数据:第一行是字符串 A,文件的第二行是字符串 B。
【输出形式】
将编辑距离 d(A,B)输出到第 1 行中。
【样例输入】
fxpimu
xwrs
【样例输出】
5
/*
--------------------------------------
--------------------------------------
---------------8829. 编辑距离问题-----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
int d[2005][2005];
/*
输入的两个字符数组为a[], b[],从下标为0开始初始化
长度分别为length_a, length_b
数组d[m][n]存放从a[1:m] 变为 b[1:n]所需要的最少操作
递归公式:
d[i][j] = 0, i=0或j=0 时(即数组的第一行和第一列均为0)
1<=i<=length_a, 1<=j<=length_b
d[i][j] = d[i-1][j-1], a[i-1] == b[j-1]
d[i][j] = min(d[i-1][j-1]+1, d[i][j-1]+1, d[i-1][j]+1), a[i-1] != b[j-1]
最优值:d[length_a][length_b]
*/
int min(int a, int b, int c)
{
int temp = a;
if(temp>b) temp = b;
if(temp>c) temp =c;
return temp;
}
int edit(char *a, char *b)
{
int length_a = strlen(a);
int length_b = strlen(b);
for(int i=0; i<=length_a; i++) d[i][0] = i;
for(int i=0; i<=length_b; i++) d[0][i] = i;
for(int i=1; i<=length_a; i++) {
for(int j=1; j<=length_b; j++) {
if(a[i-1] == b[j-1])
d[i][j] = min(d[i-1][j-1], d[i][j-1]+1, d[i-1][j]+1);
else
d[i][j] = min(d[i-1][j-1]+1, d[i][j-1]+1, d[i-1][j]+1);
}
}
return d[length_a][length_b];
}
int main()
{
char a[2000], b[2000];
cin>>a>>b;
cout<<edit(a,b);
}
圈乘运算问题
【问题描述】
关于整数的 2 元圈乘运算⊗定义为(X⊗Y)=10 进制整数 X 的各位数字之和 * 10 进制整数 Y 的最大数字+Y 的最小数字。例如,(9⊗30)=9*3+0=27。对于给定的 10 进制整数 X 和 K,由 X 和⊗运算可以组成各种不同的表达式。试设计一个算法,计算出由 X 和⊗运算组成的值为 K 的表达式最少需用多少个⊗运算。
算法设计:
给定 10 进制整数 X 和 K (1≤X,K≤1020) 。计算由 X 和⊗运算组成的值为 K 的表达式最少需用多少个⊗运算。
【输入形式】
输入数据:每一行有 2 个 10 进制整数 X 和 K。最后一行是 0 0(以0 0结束)。
【输出形式】
将找到的最少⊗运算个数输出。
【样例输入】
3 12
0 0
【样例输出】
1
这题TLE了,明天蓝桥,之后AC了再补上
/*
--------------------------------------
--------------------------------------
---------------8911. 圈乘运算问题-----
--------------------------------------
----------------------Author----------
--------------------------------------
----------------------XZITXX----------
--------------------------------------
*/
#include <bits/stdc++.h>
using namespace std;
const int MAX=81*30+9,MIN=-1;
int NumLen(int x){
//统计位数
int len = 0;
while (x>0){
len++;
x /= 10;
}
return len;
}
void Init(int* a, int x){
//作初始化
int min = 10;
int max = 0;
int num = 0;
int tend = 0;
while (x > 0){
tend = x % 10;
x /= 10;
num += tend;
if (tend > max){
max = tend;
}
if (tend < min){
min = tend;
}
}
a[0] = MAX;//存放最小圈乘次数
a[1] = num;//存放各位数之和
a[2] = min;//存放最小的数
a[3] = max;//存放最大的数
}
int main()
{
int x,k;
while(~scanf("%d%d",&x,&k)&&x!=0&&k!=0)
{
int n = NumLen(x);//表示x的位数
int m = 81*n+9;//b最小可以2为数组合,最大为9,最小为9.所以(x的各位数相加)*9+9;x的各位数相加最大为9*n;
if(m<177){
//因为y可能是2位数,导致1位数的x圈乘后的结果为2位数
m = 177;
}
if (k>m){
//若k大于x的最大圈乘数则退出
return -1;
}
int** r = new int*[m+2];//建立二维数组
for (int i=0; i<m+1; i++){
//遍历每
r[i] = new int[4];
Init(r[i],i);
}
r[m+1] = new int[4];
Init(r[m+1], x);//将起始x写到数组的最后
r[m+1][0] = 0;//变成自己不需要圈乘
//开始操作
int flag = 1;
while (flag){
//不断在序列中更新
flag = 0;
for (int i=1; i<=m+1; i++){
//寻找X
if (r[i][0] < MAX){
for (int j=1; j<=m+1; j++){
//寻找Y
if (r[j][0] < MAX){
int tend = r[i][1] * r[j][3] + r[j][2];//计算圈乘结果
if (r[tend][0]>r[i][0]+r[j][0]+1){
//与原来的圈乘生产该数的次数对比找最小
flag = 1;//若有变化则更新x的寻值
r[tend][0] = r[i][0] + r[j][0] + 1; //r[i][0]为得到x的圈乘次数,r[j][0]位得到y的圈乘次数
}//endif
}//endif
}
}//endif
}
}
cout << r[k][0] << endl;
}
return 0;
}