P2754 [CTSC1999]家园

传送门

人在各个太空站流动,所以显然的网络流模型

因为不同时间能走的边不同,所以显然按时间拆点

但是因为不知道要多少时间,所以要枚举时间,动态拆点

每一点向下一个时间的同一点连流量为 $INF$ 的边,表示时间的转移

因为知道时间,所以可以求出每站的下一站,流量显然就是对应太空船的容量

每多一时间就拆一波点

不用每次都把图重建,每次在残量网络上继续跑就好了

当最大流大于或等于总人数时就的时间就是答案

用并查集判断源点和汇点是否联通,判断是否有解

时间复杂度$O(能过)$,空间复杂度玄学

跑得还挺快...

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e5+7,INF=1e9+7;
int fir[N],from[N<<2],to[N<<2],val[N<<2],cntt=1;
inline void add(int a,int b,int c)
{
    from[++cntt]=fir[a]; fir[a]=cntt;
    to[cntt]=b; val[cntt]=c;
    from[++cntt]=fir[b]; fir[b]=cntt;
    to[cntt]=a; val[cntt]=0;
}
int n,m,K,S,T,tot;
int dep[N];
queue <int> q;
bool BFS()
{
    for(int i=0;i<=tot;i++) dep[i]=0;
    q.push(S); dep[S]=1;
    while(!q.empty())
    {
        int x=q.front(); q.pop();
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(dep[v]||!val[i]) continue;
            dep[v]=dep[x]+1; q.push(v);
        }
    }
    return dep[T] ? 1 : 0;
}
int DFS(int x,int mif)
{
    if(x==T||!mif) return mif;
    int fl=0,res=0;
    for(int i=fir[x];i;i=from[i])
    {
        int &v=to[i]; if(dep[v]!=dep[x]+1) continue;
        if( res=DFS(v,min(mif,val[i])) )
        {
            fl+=res; mif-=res;
            val[i]-=res; val[i^1]+=res;
            if(!mif) break;
        }
    }
    return fl;
}
//以上最大流模板
struct Ship{//存太空船的信息
    int sz,t;//容纳人数和经过站点的数量
    vector <int> v;//太空船经过的太空站
}p[233];
int fa[N];//并查集
inline int find(int x) { return x==fa[x] ? x : fa[x]=find(fa[x]); }
int ans,mxf;
int main()
{
    n=read()+2,m=read(),K=read();
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        p[i].sz=read(),p[i].t=read();
        for(int j=1;j<=p[i].t;j++)
        {
            int a=read();
            if(a==-1) a=n;
            if(a==0) a=n-1;
            p[i].v.push_back(a);
        }
        for(int j=1;j<p[i].t;j++)
        {
            int xa=find(p[i].v[j]),ya=find(p[i].v[0]);
            if(xa!=ya) fa[xa]=ya;
        }
    }
    if(find(n-1)!=find(n)) { printf("0"); return 0; }
    S=n-1; tot=n;
    while(1)//枚举时间
    {
        for(int i=1;i<=n;i++) add(tot-n+i,tot+i,INF);
        for(int i=1;i<=m;i++)
            add(tot-n+p[i].v[ ans%p[i].t ],tot+p[i].v[ (ans+1)%p[i].t ],p[i].sz);
        tot+=n; T=tot; ans++;
        while(BFS()) mxf+=DFS(S,INF);
        if(mxf>=K) break;
    }
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/10351448.html