Gym - 101170I Iron and Coal (思维)

  给一个有向图,然后一些点有铁一些点有煤,然后问你从1走,至少花费多少(走一个没走过的点花费1,走过的点再走一次是不用花费的)可以拿到一个铁一个煤,点可以重复走。

  枚举从1节点到一个铁一个煤的交叉点即可,三遍bfs处理出dis[1,2,3][i]分别表示1号点到i的最小花费,i到铁的最小花费,i到煤的最小花费。

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define PI acos(-1)
#define eps 1e-8
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int> pii;
const int inf=1e8;
const int maxn=1e5+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
//int lowbit(int x){return x&-x;}
//void add(int x,int v){while(x<=n)bit[x]+=v,x+=lowbit(x);}
//int sum(int x){int ans=0;while(x>=1) ans+=bit[x],x-=lowbit(x);return ans;}
inline ll read() {
    ll s = 0,w = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
        s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
inline void write(ll x) {
    if(x < 0)
        putchar('-'), x = -x;
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}

int dis[4][maxn],vis[maxn],n;
vector<int>g[maxn],ng[maxn];


void bfs1(){
    queue<int>q;
    while(!q.empty()) q.pop();
    for(int i=1;i<=n+5;i++) vis[i]=0;
    q.push(1);
    vis[1]=1;
    dis[1][1]=0;
    while(!q.empty()){
        int u=q.front(),v;q.pop();
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(vis[v]) continue;
            vis[v]=1;
            dis[1][v]=dis[1][u]+1;
            q.push(v);
        }
    }
}
void bfs2(){
    queue<int>q;
    while(!q.empty()) q.pop();
    for(int i=1;i<=n+5;i++) vis[i]=0;
    q.push(n+1);
    vis[n+1]=1;
    dis[2][n+1]=0;
    while(!q.empty()){
        int u=q.front(),v;q.pop();
        for(int i=0;i<ng[u].size();i++){
            int v=ng[u][i];
            if(vis[v]) continue;
            if(u==n+1)
                dis[2][v]=dis[2][n+1];
            else
                dis[2][v]=dis[2][u]+1;
            vis[v]=1;
            q.push(v);
        }
    }
}
void bfs3(){
    queue<int>q;
    while(!q.empty()) q.pop();
    for(int i=1;i<=n+5;i++) vis[i]=0;
    q.push(n+2);
    vis[n+2]=1;
    dis[3][n+2]=0;
    while(!q.empty()){
        int u=q.front(),v;q.pop();
        for(int i=0;i<ng[u].size();i++){
            int v=ng[u][i];
            if(vis[v]) continue;
            if(u==n+2)
                dis[3][v]=dis[3][n+2];
            else
                dis[3][v]=dis[3][u]+1;
            vis[v]=1;
            q.push(v);
        }
    }
}
int main(){
    int m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        dis[1][i]=dis[2][i]=dis[3][i]=inf;
    }
    for(int i=1;i<=m;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        ng[n+1].push_back(tmp);
    }
    for(int i=1;i<=k;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        ng[n+2].push_back(tmp);
    }
    for(int i=1;i<=n;i++){
        int tmp,v;
        scanf("%d",&tmp);
        while(tmp--){
            scanf("%d",&v);
            g[i].push_back(v);
            ng[v].push_back(i);
        }
    }
   // fuck(333);
    bfs1();
    bfs2();
    bfs3();
    int ans=inf;
   // fuck(233);
    for(int i=1;i<=n;i++){
        //cout<<dis[1][i]<<"  "<<dis[2][i]<<"  "<<dis[3][i]<<"  "<<endl;
        ans=min(ans,dis[1][i]+dis[2][i]+dis[3][i]);
    }
    if(ans==inf)
        puts("impossible");
    else
        write(ans),puts("");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值