[codeforces][gym101059C]Gangsters

time limit per test:5.0 s
memory limit per test:64 MB

You live in a graph G, with N vertices and M edges. P of these vertices have gangsters living on them. You owe each gangster some money, given by the array C (of size P). You wish to travel from s to t. If you step within distance k of any gangster who you haven’t paid, you die. We define the length of a path as then number of edges it comprises. We define the distance of two nodes as the length of the shortest path connecting them. Further, we define the cost of travelling as the sum of gangster debts you pay off. Of course, you wish to minimise the cost of travelling from s to t without dying. Note that you may not die at s or t either.

Input

First line contains four integers, N N , M, P P , and K. (1N,M,K105,1P10) ( 1   ≤   N ,   M ,   K   ≤   10 5 ,   1   ≤   P   ≤   10 ) Second line contains P integers, the locations of the gangsters. Third line contains P integers, the array C  (1Ci109) ( 1   ≤   C i   ≤   10 9 ) Each of the next M line contains two integers, xi and yi, which mean that there exists an edge between the nodes xi and yi. The last line contains two integers, s and t, the source and the target. It is guaranteed that a solution always exists.

Output

A single integer, the minimum cost of travelling from s s to t.
Example
Input

5 5 1 1
4
100
1 2
2 3
3 4
3 5
4 5
1 5

Output

100

Note

For the given example, the graph looks like
这里写图片描述
Note that the gangster is at distance 1 from the nodes 5 and 3, both of which must be visited.

题意:
给定N个点M条边的无向图,你欠P个海盗每个海盗Ci的钱,给出每个海盗的老巢,然后每个海盗能够控制距离他老巢距离<=k的所有点。k已经给出。求问至少要还多少钱才能从 s s 走到t

题解:
枚举还钱的状态,bfs看看能不能从 s s 走到t,
记得用C++ 5.1.0其他版本貌似会TLE
虽然C++ 5.1.0跑了4991ms但是好歹过了
卡时间过的emmmmm

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cstdlib>
#define LiangJiaJun main
#define ll long long
#define MOD 100000000
#define INF 19991227000000LL
using namespace std;
int ne,h[100004],dis[100004];
int n,m,p,k;
struct edge{
    int to,nt;
}e[300004];
int con[100004],P[14],c[14];
void add(int u,int v){
     e[++ne].to=v;e[ne].nt=h[u];
     h[u]=ne;
}
queue<int>q;
void trol(int tips,int x,int now,int k){
     con[x]|=(1<<(tips-1));
     if(now>=k)return ;
     for(int i=h[x];i;i=e[i].nt){
         if(con[e[i].to]&(1<<(tips-1)))continue;
         trol(tips,e[i].to,now+1,k);
     }
}
bool check(int x,int sta){
     int sx=con[x];
     for(int i=0;i<p;i++){
         if((sx&(1<<i))&&(!(sta&(1<<i))))return 0;
     }
     return 1;
}
ll  calc(int sta){
    ll ans=0;
    for(int i=1;i<=p;i++){
        if(sta&(1<<(i-1)))ans+=c[i];
    }
    return ans;
}
bool bfs(int s,int t,int sta){
     memset(dis,0,sizeof(dis));
     if((!check(s,sta))||(!check(t,sta)))return 0;
     while(!q.empty())q.pop();
     q.push(s);
     dis[s]=1;
     while(!q.empty()){
         int x=q.front();q.pop();
         for(int i=h[x];i;i=e[i].nt){
             if(!dis[e[i].to]&&check(e[i].to,sta)){
                dis[e[i].to]=1;
                q.push(e[i].to);
             }
         }
     }
     return (dis[t]!=0);
}

int w33ha(){
    n=0;
    memset(h,0,sizeof(h));
    memset(con,0,sizeof(con));
    for(int i=1;i<=p;i++)scanf("%d",&P[i]);
    for(int i=1;i<=p;i++)scanf("%d",&c[i]);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    for(int i=1;i<=p;i++)trol(i,P[i],0,k);
    int S,T;
    scanf("%d%d",&S,&T);
    ll ans=INF;
    for(int Sa=0;Sa<(1<<p);Sa++){
        if(bfs(S,T,Sa))ans=min(ans,calc(Sa));
    }
    printf("%I64d\n",ans);
    return 0;
}
int LiangJiaJun(){
    while(scanf("%d%d%d%d",&n,&m,&p,&k)!=EOF)w33ha();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值