跳转至

用最短路模型解决问题

例题 #1 [USACO04DEC] Cleaning Shifts S

一天有 \(T(1\le T\le 10^6)\) 个时段。约翰正打算安排他的 \(N(1\le N\le 2.5\times 10^4)\) 只奶牛来值班,打扫打扫牛棚卫生。每只奶牛都有自己的空闲时间段 $ S_i,E_i$,只能把空闲的奶牛安排出来值班。而且,每个时间段必需有奶牛在值班。

那么,最少需要动用多少奶牛参与值班呢?如果没有办法安排出合理的方案,就输出 \(-1\)

\(1\le T\le 10^6\)\(N\le 2.5\times 10^4\)\(1\le S_i\le E_i\le T\)

\(\text{Update On 2023/08/08}\):添加了一组hack数据,详情见这里。叉掉了时间复杂度为 \(\mathcal O(nt)\) 的错解。


我们考虑对于每个区间[a,b]从a-1→b连一条v=1的边。然后为了解决从区间内部插入的情况,对于每个i,建边i→i-1,v=0。跑最短路即可。

const int N = 3e5 + 5;
const int INF = 1e18;
const int M = 1e7;
const int MOD = 1e9 + 7;

bool FLA;

struct node{
    itn v,w;
};
vector<node> e[N];
int d[N];
int n,t;
priority_queue<pii> pq;
int vis[N];

bool FLB;
void djstr(int s){
    for(itn i=0;i<=t;i++){
        d[i]=INF;
    }
    d[s]=0;
    pq.push(mp(d[s],s));
    while(pq.size()){
        int x=pq.top().ps;
        pq.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(auto v:e[x]){
            if(!vis[v.v]&&d[v.v]>d[x]+v.w){
                d[v.v]=d[x]+v.w;
                pq.push(mp(-d[v.v],v.v));
            }
        }
    }
}


void add(int a,itn b,int c){
    e[a].pb({b,c});
//  e[b].pb({a,c});
}
void solve(){
    cerr<<((&FLB)-(&FLA))/1024.0/1024.0<<" Mib"<<endl;

    n=rd;
    t=rd;
    for(itn i=1;i<=n;i++){
        int a=rd,b=rd;
        add(a-1,b,1);
    }
    for(int i=1;i<=t;i++){
        add(i,i-1,0);
    }

    djstr(0);

    if(d[t]==INF)cout<<-1<<endl;
    else cout<<d[t]<<endl;
}

signed main() {
    // freopen(".in","r",stdin);
    // freopen(".in","w",stdout);

    int T=1;
    while(T--){
        solve();
    }
    return 0;
}