等会回来写= =
主要就是考虑用时间建点吧orz剩下等会儿回来敲。
题意
有n个空间站,地球和月球,有m个飞船在空间站和地球月球之间周期移动。对于飞船i,有一个活动表和限载人数。当一个周期结束后,飞船移动到第一个点继续。
求最少的时间把所有人疏散出去。
分析
首先其实无解什么的很好判所以不管了。
需要注意的就是对于每个飞船可以看做在某一特定时间会在空间站之间产生一条流量为限载人数的边,然后看最少在什么时候可以流完。
然后考虑枚举时间,然后加边。
然后建点的时候以(tim,x)表示时间为tim,位置在x建一个点。
枚举时间,产生边,每次在原来基础上跑一次最大流,然后瞎搞。
结束。
code
#include<bits/stdc++.h>
using namespace std;
void read(int &x){
x=0; char c=getchar(); int p=1;
for (;c<48;c=getchar())if (c=='-')p=-1;
for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
x*=p;
}
#define M 2005
#define inf 1000000
struct ed{
int x,cap,nx;
}e[M*M];
int nx[M],ecnt;
void add(int x,int y,int cap){
e[ecnt]=(ed){y,cap,nx[x]};
nx[x]=ecnt++;
e[ecnt]=(ed){x,0,nx[y]};
nx[y]=ecnt++;
}
struct Dinic{
int Flow,nnx[M],level[M],Q[M],l,r,s,t;
bool bfs(int x){
l=r=0;
memset(level,0,sizeof(level));
level[x]=1;
Q[r++]=x;
for (;l<r;){
x=Q[l++];
for (int i=nx[x];~i;i=e[i].nx)if (e[i].cap>0&&!level[e[i].x]){
level[e[i].x]=level[x]+1;
Q[r++]=e[i].x;
if (e[i].x==t)return 1;
}
}
return level[t]>0;
}
int dfs(int x,int f){
if (x==t)return f;
int sum=0;
for (int &i=nnx[x];~i;i=e[i].nx)if (e[i].cap>0&&level[e[i].x]==level[x]+1){
int d=dfs(e[i].x,min(f-sum,e[i].cap));
e[i].cap-=d; e[i^1].cap+=d;
sum+=d;
if (sum==f)return f;
}
if (!sum)level[x]=0;
return sum;
}
void solve(int ss,int tt){
s=ss; t=tt;
for (;bfs(s);){
memcpy(nnx,nx,sizeof(nx));
Flow+=dfs(s,inf);
}
}
}dinic;
int h[105],r[105],a[105][105];
int main(){
// freopen("LOJ6015.in","r",stdin);
int n,m,k,s=0,t=M-1,x,y;
read(n); read(m); read(k);
memset(nx,-1,sizeof(nx));
for (int i=1;i<=m;i++){
read(h[i]); read(r[i]);
for (int j=0;j<r[i];j++){
read(a[i][j]);
if (a[i][j]==0)a[i][j]=1+n;
if (a[i][j]==-1)a[i][j]=2+n;
}
}
if (k==0){
printf("0\n");
return 0;
}
add(s,1+n,k); add(2+n,t,k);
n+=2;
for (int i=1;i<=n*m;i++){
add(i*n+n,t,inf);
for (int j=1;j<=n;j++){
add((i-1)*n+j,i*n+j,inf);
}
for (int j=1;j<=m;j++){
x=a[j][(i+r[j]-1)%r[j]]; y=a[j][i%r[j]];
add((i-1)*n+x,i*n+y,h[j]);
}
dinic.solve(s,t);
if (dinic.Flow==k){
printf("%d\n",i);
return 0;
}
}
printf("0\n");
return 0;
}