洛谷.2754.星际转移问题(最大流Dinic 分层)

时间:2022-04-28 00:34:46

题目链接

枚举时间

每一个时间点 对于每个之前的位置像当前位置连边,表示这一时刻可待在原地

每艘船 之前时刻位置向当前时刻连边

注意别漏了0时刻src连向earth的边

#include<cstdio>
#include<cctype>
#include<algorithm>
#define gc() getchar()
const int T=501,N=17*T,M=25*T,INF=1e7; int n,m,k,src,des,v[25],num[25],pos[25][20];
int Enum,H[N],nxt[M<<1],to[M<<1],cap[M<<1],q[N],lev[N],cur[N]; inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
inline void AddEdge(int u,int v,int w)
{
to[++Enum]=v, nxt[Enum]=H[u], cap[Enum]=w, H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], cap[Enum]=0, H[v]=Enum;
}
bool BFS(int mx)//这个上界别搞错。。
{
for(int i=0;i<=mx;++i) lev[i]=0,cur[i]=H[i];
lev[des]=0;//, cur[des]=H[des];
lev[src]=1, q[0]=src;
int h=0,t=1;
while(h<t)
{
int x=q[h++];
for(int i=H[x];i;i=nxt[i])
if(!lev[to[i]] && cap[i])
{
lev[to[i]]=lev[x]+1, q[t++]=to[i];
if(to[i]==des) return 1;
}
}
return 0;
}
int Dinic(int u,int flow)
{
if(u==des) return flow;
int used=0;
for(int &i=cur[u];i;i=nxt[i])
if(lev[to[i]]==lev[u]+1 && cap[i])
{
int delta=Dinic(to[i],std::min(cap[i],flow-used));
if(delta)
{
cap[i]-=delta, cap[i^1]+=delta, used+=delta;
if(used==flow) return flow;
}
}
lev[u]=0;
return used;
} int main()
{
n=read()+2,m=read(),k=read();
Enum=1, src=0, des=7501;
for(int i=1;i<=m;++i)
{
v[i]=read(), num[i]=read();
for(int j=0;j<num[i];++j)
{
pos[i][j]=read();
if(!pos[i][j]) pos[i][j]=n-1;
else if(pos[i][j]==-1) pos[i][j]=n;
}
}
int res=0,tot=0;
AddEdge(src,n-1,INF);//,AddEdge(n,des,INF);
while(++res<500)
{
AddEdge(src,res*n+n-1,INF), AddEdge(res*n+n,des,INF);
for(int i=1;i<n;++i)
AddEdge((res-1)*n+i,res*n+i,INF);
for(int i=1;i<=m;++i)
AddEdge((res-1)*n+pos[i][(res-1)%num[i]],res*n+pos[i][res%num[i]],v[i]);
while(BFS((res+1)*n)) tot+=Dinic(src,INF);
if(tot>=k) break;
}
if(res==500) putchar('0');
else printf("%d",res); return 0;
}