luogu P5340 [TJOI2019]大中锋的游乐场

传送门

要求经过路径汉堡的点和可乐的点个数之差绝对值\(\le k\),所以可以考虑dp,\(f_{i,j}\)表示到点\(i\),汉堡的点个数减可乐的点的个数为\(j\)的最短距离,注意一下负下标处理,然后跑个dij就完事了

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double

using namespace std;
const int N=1e4+10,M=1e5+10,mod=998244353;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[M<<1],nt[M<<1],w[M<<1],hd[N],tot;
void add(int x,int y,int z)
{
    ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
    ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
}
int n,m,kk,a[N];
LL di[N][21];
struct node
{
    int x,k;
    LL d;
    bool operator < (const node &bb) const {return d>bb.d;}
};
priority_queue<node> q;

int main()
{
    int T=rd();
    while(T--)
    {
        n=rd(),m=rd(),kk=rd();
        for(int i=1;i<=n;++i) a[i]=rd()&1?-1:1;
        memset(hd,0,sizeof(hd)),tot=1;
        while(m--)
        {
            int x=rd(),y=rd(),z=rd();
            add(x,y,z);
        }
        memset(di,0x3f,sizeof(di));
        int ps=rd(),pt=rd();
        if(kk+a[ps]>=0&&kk+a[ps]<=kk+kk)
            q.push((node){ps,kk+a[ps],di[ps][kk+a[ps]]=0});
        while(!q.empty())
        {
            int x=q.top().x,k=q.top().k;
            LL d=q.top().d;
            q.pop();
            if(d>di[x][k]) continue;
            for(int i=hd[x];i;i=nt[i])
            {
                int y=to[i],nk=k+a[y];
                if(nk>=0&&nk<=kk+kk&&di[y][nk]>di[x][k]+w[i])
                    q.push((node){y,nk,di[y][nk]=di[x][k]+w[i]});
            }
        }
        LL ans=1ll<<50;
        for(int i=0;i<=kk+kk;++i) ans=min(ans,di[pt][i]);
        ans<(1ll<<50)?printf("%lld\n",ans):puts("-1");
    }
    return 0;
}
posted @ 2019-05-09 21:39  ✡smy✡  阅读(116)  评论(0编辑  收藏  举报