恋与程序员

链接: https://www.nowcoder.com/acm/contest/67/E
来源:牛客网

题目描述

    马云:“哈哈,女生的钱最好赚了!”

    叠纸:“马云说得对!”

    腾讯:“哇!真的耶!求代理!”

    小P眼一眯,嘴角一挑,似乎发现了商机。不就是抽卡过关看CG么,我也能做啊!于是乎,一个月后,一款《恋与程序员》诞生了。

    游戏里设置了n个事件,m个关卡,k张卡片。每一个事件都有一张独一无二的CG,但是每个关卡,都需要拥有特定的卡片才能通关。从一个事件,触发另一个事件,需要通过一个特定的关卡。我们给事件编号为1~n,对应的CG编号与事件的编号一致。卡片编号为1~k。一开始,玩家会触发事件1,并拿到1号CG,但是从此之后,玩家如果想触发别的事件,便要通过闯关来达到。

    现在,小Q想要c号CG(触发c号事件获得),但是小Q却又不想花太多的钱。于是小Q查了攻略,以事件为点,关卡为边,作了一张图,并且小Q知道每个关卡都需要什么卡片以及卡片的售价。请你计算一下,小Q拿到c号CG,至少要花多少钱。

    注意,过关并不需要消耗卡片,同一张卡片可以通关多次。

输入描述:

数据有多组,处理到文件结束。
每组数据第一行有四个整数n,m,k,c,代表事件数量、关卡数量、卡片数量以及小Q想要的CG的编号。
接下来m行,每行三个整数u,v,e,代表从u号事件可以通过闯关触发v号事件,并且需要e号卡片。
接下来k行,每行两个整数a,b,代表a号卡片的售价是b。

输出描述:

每组数据输出一行,一个整数,代表小Q拿到c号CG的最小花费。
示例1

输入

6 7 5 6
2 3 2
4 3 3
1 2 1
1 5 4
4 6 5
1 4 2
5 6 3
1 100
3 422
2 210
5 107
4 38

输出

317


题意:略


思路:一开始想的是求1到c的最短路的长度,并存下路径,若同一张卡片用到多次减去多用的费用即可,但这样卡80%,后来想了想,发现还有一种情况:


这样就不是求最短路了。所以求最短路这种想法是错误的。


后来一想,其实一个DFS就可以了,把买过的卡片用vis[ ]标记一下即可。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int INF = 1e9;

int n,m,k,c;
int map[120][120];
int val[120];
int vis[120];
int ans,tmp;

void dfs(int root,int fa)
{
    //得到最终想要的CG
    if(root==c)
    {
        ans=min(ans,tmp);
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(map[root][i])
        {
            if(i==fa)
                continue;
            //若这张卡片之前没买过就买
            if(!vis[map[root][i]])
            {
                vis[map[root][i]]=1;
                tmp+=val[map[root][i]];
                dfs(i,root);
                //这种情况考虑完了之后恢复初始值
                vis[map[root][i]]=0;
                tmp-=val[map[root][i]];
            }
            //买过了就不用再买
            else
            {
                dfs(i,root);
            }
        }
    }
    return;
}

int main()
{
    while(scanf("%d%d%d%d",&n,&m,&k,&c)!=EOF)
    {
        memset(map,0,sizeof(map));
        memset(val,0,sizeof(val));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int u,v,e;
            scanf("%d%d%d",&u,&v,&e);
            map[u][v]=e;
        }
        for(int i=1;i<=k;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            val[a]=b;
        }
        tmp=0;
        ans=INF;
        dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值