题目
题意: 略。
思路: 首先用并查集或者dfs的方式判断起点和终点是否连通。之后呢,感觉这个题比较难建图。一个比较好的想法是根据天来建图,每一天建立所有点,不同天同一个点之间建立INF的边(停在某个点的人可以再留一天),再根据每趟车建立某一天的点和下一天的点之间的连边。之后天数从1开始增加即可,因为网络流是可扩展的,新增加了某一天的边之后再跑网络流并不慢。除此之外,建立超级源点和超级汇点,超级源点向第0天的起点连一条流量为k的边;所有天的终点向超级汇点连一条流量为INF的边。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 15*15*50+100;
const int M = 2*(20+15+1)*(15+1)*51;
const int INF = 1e9;
int q[N],cur[N],d[N];
int h[N],e[M],ne[M],w[M],idx = 0;
int n,m,k,T; int st,ed;
void add(int a,int b,ll c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
bool bfs()
{
int hh = 0,tt = 0;
memset(d,-1,sizeof(d));
d[st] = 0,cur[st] = h[st],q[tt++] = st;
while(hh!=tt)
{
int u = q[hh++];
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(d[j]==-1&&w[i])
{
d[j] = d[u] + 1;
cur[j] = h[j];
if(j==ed) return true;
q[tt++] = j;
}
}
}
return 0;
}
ll find(int u,ll limit)
{
if(u==ed) return limit;
ll flow = 0;
for(int i=cur[u];~i&&flow<limit;i=ne[i])
{
cur[u] = i;
int j = e[i];
if(d[j]==d[u]+1&&w[i])
{
ll t = find(j,min(1ll*w[i],limit-flow));
if(!t) d[j] = -1;
flow += t; w[i] -= t,w[i^1] += t;
}
}
return flow;
}
ll dinic()
{
ll ans = 0,flow;
while(bfs()) while(flow = find(st,INF)) ans += flow;
return ans;
}
int get(int day,int id) //第day天的id节点
{
return day*(n+2)+id;
}
int a[22]; //容量
vector<int> va[22]; //节点
int fa[22];
int find(int x)
{
return x==fa[x]?x:fa[x] = find(fa[x]);
}
void solve()
{
memset(h,-1,sizeof(h));
cin>>n>>m>>k;
st = 0,ed = N-1;
for(int i=1;i<=n+2;++i) fa[i] = i;
for(int i=0;i<m;++i)
{
cin>>a[i];
int num; cin>>num;
while(num--)
{
int x; cin>>x;
if(x==-1) x = n+2;
else x++;
va[i].push_back(x);
}
}
for(int i=0;i<m;++i)
{
for(int j=0;j<va[i].size()-1;++j)
{
int l = va[i][j];
int r = va[i][j+1];
int u = find(l),v = find(r);
if(u!=v)
{
fa[v] = u;
}
}
}
if(find(n+2)!=find(1))
{
cout<<0; return;
}
add(st,get(0,1),k);
add(get(0,1),st,0);
int now = 0; int ans = 0;
while(now <= 1000)
{
add(get(now+1,n+2),ed,INF); //第0天必没有流量,下一天的月球
add(ed,get(now+1,n+2),0);
for(int i=1;i<=n+1;++i)
{
add(get(now,i),get(now+1,i),INF); //待一天
add(get(now+1,i),get(now,i),0);
}
for(int i=0;i<m;++i)
{
int l = va[i][now%va[i].size()];
int r = va[i][(now+1)%va[i].size()];
// cout<<l<<" "<<r<<"\n";
add(get(now,l),get(now+1,r),a[i]); //传输
add(get(now+1,r),get(now,l),0);
}
ans += dinic();
// cout<<now<<":"<<ans<<"\n";
now ++ ;
if(ans == k) break;
}
cout<<now;
}
signed main(void)
{
solve();
return 0;
}
/*
3 2 1 3
1 2 1000 2000
2 3 100 200
*/