ACM 227. [POI1997] 阿里巴巴(BFS)

227. [POI1997] 阿里巴巴

★☆   输入文件: ali.in   输出文件: ali.out    简单对比
时间限制:1 s   内存限制:128 MB

想要“芝麻开门”,必须拥有一定数量的钱币,其中包括至少z枚金币,s枚银币和m枚铜币。 最初,阿里巴巴拥有三种钱币若干枚。他可以按照一定规则和芝麻之门的守护者进行交易。 每一种规则用以下形式表示:

z1, s1, m1 -> z2, s2, m2 (zi, si, mis属于集合{0,1,2,3,4})。

这样一种规则表示阿里巴巴可以将z1枚金币, s1枚银币, m1枚铜币换成z2枚金币, s2枚银币, m2枚铜币。 一次交易而得的钱币可以继续参加下一次的交易。

任务

从文件中读入几组数据;对于每一组数据:

  • 阿里巴巴最初拥有的金银铜三种钱币数目
  • “芝麻开门”所需的金银铜三种钱币数目
  • 所有交易规则

对每一组数据,判断是否存在有限次的交易,使阿里巴巴能开启芝麻之门。如果是,则将最少交易次数输出,否则在输出NIE(波兰文NO)

把结果写进文件中

输入格式 文件的第一行有一个整数d<=10,表示数据的组数。

接下来是d组数据,每组占若干行。

第一行是三个数zp, sp, mp ,属于集合{0,1,2,3,4}。表示阿里巴巴最初拥有的金银铜数目。

第二行是三个数z, s, m , 属于集合{0,1,2,3,4}。表示芝麻开门所需的金银铜数目。

第三行是规则总数r,1<=r<=10。

以下r行每行有六个数z1, s1, m1, z2, s2, m2 ,属于集合{0,1,2,3,4}。表示一种简单的交易z1, s1, m1 -> z2, s2, m2。

数字之间由若干个空格隔开。

输出格式

文件的第i行为第i组数据的答案:

一个非负整数——阿里巴巴要开启芝麻之门所需的最少交易次数,或者

单词NIE(波兰文NO)

样例输入

2
2 2 2
3 3 3
3
0 1 1 2 0 0
1 0 1 0 2 0
1 1 0 0 0 2
1 1 1
2 2 2
4
1 0 0 0 1 0
0 1 0 0 0 1
0 0 1 1 0 0
2 0 0 0 2 2

样例输出

NIE
9

由于状态比较多使用链式队列,vis三维数组判重
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

#define MAX_R 10

int d;
int zp,sp,mp;
int z,s,m;
int r;
struct Business
{
    int zp,sp,mp;
    int zt,st,mt;
} Bus[MAX_R];
struct Node
{
    int z,s,m;
    int times;
    Node *pNext;
};
Node Front,*pRear;
bool vis[100][100][100];

bool Empty()
{
    return Front.pNext==NULL;
}

void Add(Node &node)
{
    pRear->pNext=new Node;
    pRear=pRear->pNext;
    pRear->pNext=NULL;
    pRear->z=node.z;
    pRear->s=node.s;
    pRear->m=node.m;
    pRear->times=node.times;
}



Node Del()
{
    Node *pDel;
    Node node;

    node=*Front.pNext;

    pDel=Front.pNext;
    Front.pNext=pDel->pNext;

    if(Front.pNext==NULL) pRear=&Front;

    delete pDel;

    return node;
}

int main()
{
    freopen("ali.in","r",stdin);
    freopen("ali.out","w",stdout);

    int ans=-1;
    scanf("%d",&d);

    while(d--)
    {
        scanf("%d%d%d",&zp,&sp,&mp);
        scanf("%d%d%d",&z,&s,&m);
        scanf("%d",&r);

        for(int i=0; i<r; i++)
        {
            scanf("%d%d%d",&Bus[i].zp,&Bus[i].sp,&Bus[i].mp);
            scanf("%d%d%d",&Bus[i].zt,&Bus[i].st,&Bus[i].mt);
        }

        Front.pNext=NULL;
        pRear=&Front;
        Node node=Node{zp,sp,mp,0,NULL};
        Add(node);

        memset(vis,0,sizeof(vis));

        while(!Empty())
        {
            Node q=Del();

            if(q.z>=z && q.s>=s && q.m>=m)
            {
                ans=q.times;
                break;
            }

            for(int i=0;i<r;i++)
            {
                Node qnew=q;

                if(qnew.z>=Bus[i].zp && qnew.s>=Bus[i].sp &&
                   qnew.m>=Bus[i].mp)
                {
                    qnew.z=qnew.z-Bus[i].zp+Bus[i].zt;
                    qnew.s=qnew.s-Bus[i].sp+Bus[i].st;
                    qnew.m=qnew.m-Bus[i].mp+Bus[i].mt;
                    qnew.times=q.times+1;

                    if(!vis[qnew.z][qnew.s][qnew.m] && qnew.z<100 && qnew.s<100 && qnew.m<100)
                    {
                        vis[qnew.z][qnew.s][qnew.m]=true;
                        Add(qnew);
                    }
                }
            }
        }

        if(ans==-1)
            printf("NIE\n");
        else
            printf("%d\n",ans);

    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值