[POI 2003] Smugglers 解题记录

[POI 2003] Smugglers 解题记录


题意简述

n n n 种金属(金子编号为 1 1 1),每种金属有自己的单价,金属之间可以互相转换,编号为 i i i 的金属转换为 j j j 需要 k k k 的代价。穿过边境花费 50 % 50\% 50% 当前的金属的单价。
问要把金子带过边境,需要的最少的代价。


题目分析

对于题目中的“ i i i j j j 花费 k k k”,很容易就可以想到建图。考虑如何建图。
可以把图分为两部分:过边境前和过边境后。
那么我们就可以设 1 ∼ n 1 \sim n 1n 为过边境前的部分, n + 1 ∼ 2 n n+1 \sim 2n n+12n 为过边境后的部分。对于金属 i i i 和金属 j j j,如果可以转换,那么就把 i i i j j j 之间连一条单向边,同时在 i + n i+n i+n j + n j+n j+n 之间也连一条单向边
对于两个部分之间的连接,其实就是扣税的过程,直接将 i i i i + n i+n i+n 连一条权值为金属 i i i 单价的 50 % 50\% 50% 的边。
最后跑一遍最短路即可。


AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=1e5+5;
struct edge {
    int to,nex,data;
}e[N<<2];//图要开4倍
int n,m,tot,head[N],dis[N];
void add(int x,int y,int z) {
    e[++tot].to=y;
    e[tot].data=z;
    e[tot].nex=head[x];
    head[x]=tot;
}
struct node {
    int to,data;
    bool operator<(const node& b)const {
        return data>b.data;
    }
};
std::priority_queue<node> q;
void dijkstra(int st) {
    mem(dis,0x3f);
    q.push(node{st,0});
    dis[st]=0;
    while(!q.empty()) {
        node u=q.top();
        q.pop();
        int x=u.to;
        if(dis[x]!=u.data) {
            continue;
        }
        erg(i,x) {
            int y=e[i].to,z=e[i].data;
            if(dis[y]>dis[x]+z) {
                dis[y]=dis[x]+z;
                q.push(node{y,dis[y]});
            }
        }
    }
}
signed main() {
    std::cin>>n;
    rep(i,1,n) {
        int x;
        std::cin>>x;
        add(i,n+i,x/2);//扣税
    }
    std::cin>>m;
    rep(i,1,m) {
        int x,y,z;
        std::cin>>x>>y>>z;
        add(x,y,z);//转换
        add(x+n,y+n,z);
    }
    dijkstra(1);
    std::cout<<dis[n+1];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值