题目大意:输入两个数,总共有三大种可能到达的状态:1.第一个数后面添加一位数(0,1,2,3...9);2.第一个数+一个数(0,1,2,3...9);3.第一个数*一个数(0,1,2,3...9);
下面3行10列分别对应到达每种状态的花费,求从第一个数变到第二个数的最小花费和最小变换次数。
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int m,n;
int a[5][20];
bool vis[100005];
int count1,count2;
struct node
{
int x;
int cost;
int step;
friend bool operator<(const node a,node b)
{ //优先选择花费小的,若花费相同,则优先选择变换次数少的
if(a.cost!=b.cost)
return a.cost>b.cost;
else
return a.step>b.step;
}
}cur,next;
int judge(int k)
{
int count=0;
while(k)
{
count++;
k/=10;
}
return count;
}
void bfs()
{
memset(vis,false,sizeof(vis));
priority_queue<node> q;
cur.x=m;
cur.cost=0;
cur.step=0;
q.push(cur);
while(!q.empty())
{
cur=q.top();
q.pop();
if(vis[cur.x])// 此题的关键
continue;
vis[cur.x]=true;// 此题的关键 利用优先队列 标记当前这个数 费用最小的状态 过滤那些 费用大于它的同一状态
if(cur.x==n)
{
printf("%d %d\n",cur.cost,cur.step);
return ;
}
for(int i=0;i<3;i++)
{
for(int j=0;j<10;j++)
{
count2=judge(cur.x);
if(i==0&&count2<count1)
{
next.x=cur.x*10+j;
}
else if(i==1)
{
next.x=cur.x+j;
}
else
{
next.x=cur.x*j;
}
if(next.x>n)
continue;
if(!vis[next.x])
{
next.cost=cur.cost+a[i][j];
next.step=cur.step+1;
q.push(next);
}
}
}
}
}
int main()
{
int t=0;
while(scanf("%d%d",&m,&n)!=EOF)
{
t++;
for(int i=0;i<3;i++)
{
for(int j=0;j<10;j++)
{
scanf("%d",&a[i][j]);
}
}
count1=judge(n);
printf("Case %d: ",t);
bfs();
}
return 0;
}