[挖坑]网络流24题
1.飞行员配对方案问题
https://www.luogu.org/problem/show?pid=2756
二分图匹配。
#include<iostream> #include<cstdio> #include<queue> #define MAXN 100 #define S 0 #define T 201 #define MAXL 10000 #define INF 200000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } struct edge{ int to,next,w; }e[2*MAXL+5]; int head[T+5]; int cnt=1,n,m,ans=0; int q[T+5]; queue<int> qu; void ins(int f,int t,int w) { e[++cnt].next=head[f]; head[f]=cnt; e[cnt].to=t; e[cnt].w=w; } void insw(int f,int t,int w) { ins(f,t,w);ins(t,f,0); } int dfs(int x,int f) { if(x==T) return f; int used=0; for(int i=head[x];i;i=e[i].next) if(e[i].w&&q[e[i].to]==q[x]+1) { int w=dfs(e[i].to,min(e[i].w,f-used)); used+=w; e[i].w-=w; e[i^1].w+=w; if(used==f) return f; } return used; } bool bfs() { qu.push(S);q[S]=0; for(int i=1;i<=T;i++) q[i]=-1; while(!qu.empty()) { int u=qu.front();qu.pop(); for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(e[i].w&&q[v]==-1) { q[v]=q[u]+1; qu.push(v); } } } return q[T]!=-1; } int main() { n=read();m=read(); int x=read(),y=read(); while(x!=-1) { insw(x,y,1); x=read();y=read(); } for(int i=1;i<=n;i++) insw(S,i,1); for(int i=1;i<=m;i++) insw(i+n,T,1); while(bfs()) ans+=dfs(S,INF); printf("%d\n",ans); for(int i=head[S];i;i=e[i].next) { if(e[i].w) continue;int v=e[i].to; for(int j=head[v];j;j=e[j].next) { if(e[j].w||e[j].to==S) continue; printf("%d %d\n",v,e[j].to); } } return 0; }
2.太空飞行计划问题
貌似是叫做最大权闭合图...最小割就可以了..
原题真的恶心,读入都不给数量的....换成了一道数据更大的类似的题目
http://www.lydsy.com/JudgeOnline/problem.php?id=1497
#include<iostream> #include<cstdio> #include<queue> #define T 60001 #define S 0 #define MAXN 60000 #define INF 2000000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } int cnt=1,ans=0,n,m; int head[MAXN+5]; struct edge{ int to,next,w; }e[5000000]; int q[MAXN+5]; queue<int> qu; void ins(int f,int t,int w) { e[++cnt].to=t; e[cnt].next=head[f]; head[f]=cnt; e[cnt].w=w; } inline void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);} bool bfs() { q[S]=0;for(int i=1;i<=T;i++) q[i]=-1; qu.push(S); while(!qu.empty()) { int u=qu.front();qu.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].w&&q[e[i].to]==-1) { q[e[i].to]=q[u]+1; qu.push(e[i].to); } } return q[T]!=-1; } int dfs(int x,int f) { if(x==T) return f; int used=0; for(int i=head[x];i;i=e[i].next) { if(e[i].w&&q[e[i].to]==q[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w; e[i].w-=w; e[i^1].w+=w; if(used==f) return f; } } return used; } int main() { m=read();n=read(); for(int i=1;i<=m;++i) {int c=read();insw(i+n,T,c);} for(int i=1;i<=n;i++) { int x=read(); insw(i,x+n,INF); x=read(); insw(i,x+n,INF); x=read(); insw(S,i,x);ans+=x; } while(bfs()) ans-=dfs(S,INF); printf("%d\n",ans); return 0; }
3.最小线段覆盖问题
最大匹配
https://www.luogu.org/problem/show?pid=2764#sub
#include<iostream> #include<cstdio> #include<queue> #define T 8001 #define S 0 #define MAXN 8000 #define INF 2000000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } int ne[MAXN+5]; bool yes[MAXN+5]; int cnt=1,ans=0,n,m; int head[MAXN+5]; struct edge{ int to,next,w; }e[4000002]; int q[MAXN+5]; queue<int> qu; void ins(int f,int t,int w) { e[++cnt].to=t; e[cnt].next=head[f]; head[f]=cnt; e[cnt].w=w; } inline void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);} bool bfs() { q[S]=0;for(int i=1;i<=T;i++) q[i]=-1; qu.push(S); while(!qu.empty()) { int u=qu.front();qu.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].w&&q[e[i].to]==-1) { q[e[i].to]=q[u]+1; qu.push(e[i].to); } } return q[T]!=-1; } int dfs(int x,int f) { if(x==T) return f; int used=0; for(int i=head[x];i;i=e[i].next) { if(e[i].w&&q[e[i].to]==q[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w; e[i].w-=w; e[i^1].w+=w; if(w) { ne[x]=e[i].to; if(e[i].to>n) yes[e[i].to-n]=1; } if(used==f) return f; } } return used; } int main() { n=read();m=read();int a,b; for(int i=1;i<=m;i++) { a=read();b=read();insw(a,b+n,1); } for(int i=1;i<=n;i++) insw(S,i,1),insw(i+n,T,1); while(bfs()) ans+=dfs(S,INF); for(int i=1;i<=n;i++) { if(yes[i]) continue; int t=i; while(t>0) { printf("%d ",t); t=ne[t]-n; } puts(""); } printf("%d\n",n-ans); return 0; }
4.魔术球问题
https://www.luogu.org/problem/show?pid=2765
这道题非常巧妙...想了好久不知道怎么构图就去看了一下题解,发现和第三题一模一样.....
把两个能叠在一起的数字连边,求的就是求 使得最短路径覆盖数=输入的K 的最大数字。
第一次交最大的点跑了950+ms 好像是卡过去的。
后来想想,这道题并不需要撤销,于是就在bfs里面加了一句只往大的数字走(就是不考虑反边),只有350ms了......
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define S 0 #define T 10000 #define N 5500 #define INF 200000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } int K,cnt=1,ans; struct edge{ int to,next,w; }e[150005]; int head[T+5]; int to[T+5]; queue<int> Q; int q[T+5]; bool mark[T+5]; void INS(int f,int t,int w) { e[++cnt].next=head[f];head[f]=cnt; e[cnt].to=t;e[cnt].w=w; } void ins(int f,int t,int w){INS(f,t,w);INS(t,f,0);} int dfs(int x,int f) { //cout<<"dfs"<<x<<" "<<f<<endl; if(x==T) return f; int used=0; for(int i=head[x];i;i=e[i].next) if(e[i].w&&q[e[i].to]==q[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); if(w>0) { used+=w; e[i].w-=w; e[i^1].w+=w; mark[e[i].to-N]=1; to[x]=e[i].to-N; } if(used==f) return used; } if(used==0) q[x]=-1; return used; } bool bfs() { for(int i=1;i<=T;i++) q[i]=-1;q[0]=0; Q.push(S); while(!Q.empty()) { int u=Q.front();Q.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].w&&q[e[i].to]==-1&&e[i].to>u) {q[e[i].to]=q[u]+1;Q.push(e[i].to);} } return q[T]!=-1; } int main() { K=read(); int j; for(ans=1,j=1;;++ans,++j) { ins(S,ans,1);ins(ans+N,T,1); for(int i=1;i*i<2*ans;i++) if(i*i>ans) ins(ans,i*i-ans+N,1); while(bfs()) j-=dfs(S,INF); if(j>K) break; } --ans;printf("%d\n",ans); for(int i=1;i<=ans;i++) { if(mark[i]) continue; int t=i; while(t) { printf("%d ",t); t=to[t]; } puts(""); } return 0; }
5.圆桌问题http://tyvj.cn/p/1325
这道题模型非常的简单....但是没地方测啊....
好不容易发现tyvj有这道题,交上去wa光了,发现居然没有spj????????
假装已经a了
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define S 0 #define T 501 #define INF 2000000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } queue<int> qu; int q[505]; int n,m,ans=0,cnt=1; int head[505]; int s[280]; struct edge{ int to,next,w; }e[100005]; void INS(int f,int t,int w) { e[++cnt].next=head[f];head[f]=cnt; e[cnt].to=t;e[cnt].w=w; } inline void ins(int f,int t,int w){INS(f,t,w);INS(t,f,0);} int dfs(int x,int f) { if(x==T) return f; int used=0; for(int i=head[x];i;i=e[i].next) if(e[i].w&&q[e[i].to]==q[x]+1) { int w=dfs(e[i].to,min(e[i].w,f-used)); e[i].w-=w;e[i^1].w+=w; used+=w;if(used==f) return used; } return used; } bool bfs() { memset(q,0,sizeof(q));qu.push(S);q[S]=1; while(!qu.empty()) { int u=qu.front();qu.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].w&&!q[e[i].to]) {q[e[i].to]=q[u]+1;qu.push(e[i].to);} } return q[T]!=0; } int main() { n=read();m=read(); for(int i=1;i<=n;i++){s[i]=read();ans+=s[i];} for(int i=n;i;i--) ins(S,i,s[i]); for(int i=1;i<=m;i++){int x=read();ins(i+n,T,x);} for(int i=1;i<=n;i++)for(int j=m;j;j--)ins(i,j+n,1); while(bfs()) ans-=dfs(S,INF); if(ans) return 0*puts("0");puts("1"); for(int i=head[S];i;i=e[i].next) { for(int j=head[e[i].to];j;j=e[j].next) if(!e[j].w&&e[j].to>n) printf("%d ",e[j].to-n); puts(""); } return 0; }
6.餐巾计划问题/bzoj1211软件开发
题解见www.cnblogs.com/FallDream/p/liu
#include<iostream> #include<cstdio> #include<cstring> #define S 0 #define T 2001 #define INF 2000000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } bool mark[T+5]; int head[T+5],cnt=1,n,ff,fa,fb,a,b,p=0,ans=0; struct edge{ int to,next,w,c; }e[12005]; void ins(int f,int t,int w,int c){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;e[cnt].w=w;e[cnt].c=c;} void insw(int f,int t,int w,int c){ins(f,t,w,c);ins(t,f,0,-c);} int dfs(int x,int f) { if(x==T) return ans+=f*p,f; int used=0; mark[x]=1; for(int i=head[x];i;i=e[i].next) if(!e[i].c&&e[i].w&&!mark[e[i].to]) { int w=dfs(e[i].to,min(f-used,e[i].w)); e[i].w-=w;e[i^1].w+=w;used+=w; if(used==f)return f; } return used; } bool modlabel() { int minn=INF; for(int i=S;i<=T;i++)if(mark[i]) for(int j=head[i];j;j=e[j].next) if(!mark[e[j].to]&&e[j].w) minn=min(minn,e[j].c); if(minn==INF)return false; for(int i=S;i<=T;i++)if(mark[i]) for(int j=head[i];j;j=e[j].next) e[j].c-=minn,e[j^1].c+=minn; p+=minn; return true; } int main() { n=read();ff=read();b=read();fb=read();a=read();fa=read(); for(int i=1;i<=n;i++) { insw(S,i,INF,ff);int x=read();insw(S,i+n,x,0);insw(i,T,x,0); if(i-a>0)insw(i+n-a,i,INF,fa); if(i-b>0)insw(i+n-b,i,INF,fb); } for(int i=1;i<n;i++)insw(i+n,i+n+1,INF,0); do do memset(mark,0,sizeof(mark)); while(dfs(S,INF));while(modlabel()); printf("%d",ans); return 0; }
7.最长递增子序列问题
https://www.luogu.org/problem/show?pid=2766
注意洛谷上的这题变成了不下降
倒着dp,求出以它为起点的最长递增序列f[i]
每个点拆两个,一个进入,一个出去,他们之间连流量1的边
然后对于f[i]=1 从S向它连流量1的边,对于f[i]=s,从它向T连流量1 对于 i<j且a[i]<=a[j]&&f[i]==f[j]+1 从i向j连流量1的边,跑一次最大流就是答案
对于第三个问,我们把1号点和n号点之间的边、向ST连的边都改成INF就可以啦。
代码不像是我写的但是确实是我写的.....
#include<iostream> #include<cstdio> #include<cstring> #define MN 2000 #define ME 1000000 #define S 0 #define T 2001 #define INF 2000000000 using namespace std; 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 * 10 + ch - '0';ch = getchar();} return x * f; } int f[MN + 5] , n , mx = 0 , s[MN + 5] , head[MN + 5] , cnt = 1 , q[MN + 5] , top = 0 , d[MN + 5] , ans = 0; struct edge{int to , next , w;}e[ME + 5]; void ins(int f , int t , int w) { e[++cnt] = (edge){t , head[f] , w};head[f] = cnt; e[++cnt] = (edge){f , head[t] , 0};head[t] = cnt; } bool bfs() { memset(d , 0 , sizeof(d));int i , j; for(d[q[i = top = 0] = S] = 1 ; i <= top ; i++) for(j = head[q[i]] ; j ; j = e[j].next) if(e[j].w && !d[e[j].to]) d[q[ ++ top ] = e[j].to]= d[q[i]] + 1; return d[T] > 0; } int dfs(int x , int f) { if(x == T) return f; int used = 0; for(int i = head[x] ; i ; i = e[i].next) if(e[i].w && d[e[i].to] == d[x] + 1) { int w = dfs(e[i].to , min(f - used , e[i].w)); used += w;e[i].w -= w;e[i^1].w += w; if(used == f) return used; } return used; } int main() { n = read(); for(int i = 1 ; i <= n ; i++) s[i] = read(); for(int i = n + 1 ; i ; mx = max(mx , f[i]) , f[--i] = 1) for(int j = i+1 ; j <= n ; j++) if(s[i] <= s[j]) f[i] = max(f[i] , f[j] + 1); for(int i = 1 ; i <= n ; i++) ins(i , i + n , 1); printf("%d\n" , mx); for(int i = 1 ; i <= n ; i++) for(int j = i + 1 ; j <= n ; j++) if(f[i] == f[j] + 1 && s[i] <= s[j]) ins(i + n , j , 1); for(int i = 1 ; i <= n ; i++) { if(f[i] == 1) ins(i + n , T , 1); if(f[i] == mx) ins(S , i , 1); } while(bfs())ans += dfs(S , INF); printf("%d\n" , ans); if(mx == 1) return 0 * printf("%d" , n); cnt = 1; ans = 0; memset(head , 0 ,sizeof(head)); for(int i = 2 ; i < n ; i++) ins(i , i + n , 1); ins(1 , 1 + n , INF);ins(n , n << 1 , INF); for(int i = 1 ; i <= n ; i++) for(int j = i + 1 ; j <= n ; j++) if(f[i] == f[j] + 1 && s[i] <= s[j]) ins(i + n , j , 1); for(int i = 1 ; i <= n ; i++) { if(f[i] == 1) ins(i + n , T , INF); if(f[i] == mx) ins(S , i , INF); } while(bfs())ans += dfs(S , INF); printf("%d\n" , ans); return 0; }
8.试题库问题
https://www.luogu.org/problem/show?pid=2763
二分图乱匹配
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define S 0 #define T 1021 #define INF 2000000000 using namespace std; 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*10+ch-'0'; ch=getchar();} return x*f; } int c[T+5],head[T+5],n,k,m,cnt=1,q[T+5],qx[T+5],top,s[T],d[T+5],ans=0; struct edge{ int to,next,w; }e[50005]; void ins(int f,int t,int w) { e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],0};head[t]=cnt; } bool bfs() { memset(d,0,sizeof(d));int i,j; for(d[q[i=top=0]=S]=1;i<=top;i++) for(int j=c[q[i]]=head[q[i]];j;j=e[j].next) if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1; return d[T]; } int dfs(int x,int f) { if(x==T)return f; int used=0; for(int&i=c[x];i;i=e[i].next) if(e[i].w&&d[e[i].to]==d[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w;e[i].w-=w;e[i^1].w+=w; if(used==f)return f; } return used; } int main() { k=read();n=read(); for(int i=1;i<=k;i++)s[i]=read(); for(int i=k;i;i--) { ans+=s[i]; ins(S,i+n,s[i]); } for(int i=1;i<=n;i++) { m=read();ins(i,T,1); for(int j=1;j<=m;j++) ins(read()+n,i,1); } while(bfs()) ans-=dfs(S,INF); if(ans) return 0*puts("No Solution!"); for(int i=head[S];i;i=e[i].next) { printf("%d: ",e[i].to-n); for(int j=head[e[i].to];j;j=e[j].next) if(!e[j].w&&e[j].to!=S) printf("%d ",e[j].to); if(e[i].next) puts(""); } return 0; }
9.方格取数问题
https://www.luogu.org/problem/show?pid=2774
#include<iostream> #include<cstdio> #include<cstring> #define S 0 #define T 10001 #define INF 2000000000 using namespace std; 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 * 10 + ch - '0';ch = getchar();} return x * f; } int n,m,cnt=1,q[T+5],d[T+5],head[T+5],c[T+5],ans=0,top; struct edge{ int to,next,w; }e[200000]; void ins(int f,int t,int w) { e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],0};head[t]=cnt; } int dfs(int x,int f) { if(x==T)return f; int used=0; for(int&i=c[x];i;i=e[i].next) if(e[i].w&&d[e[i].to]==d[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w;e[i].w-=w;e[i^1].w+=w; if(used==f)return f; } return used; } bool bfs() { memset(d,0,sizeof(d));int i,j; for(d[q[i=top=0]=S]=1;i<=top;i++) for(int j=c[q[i]]=head[q[i]];j;j=e[j].next) if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1; return d[T]; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int x=read();ans+=x; if((i+j)&1) ins(S,(i-1)*m+j,x); else ins((i-1)*m+j,T,x); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((i+j)&1) { int x=(i-1)*m+j; if(i>1) ins(x,(i-2)*m+j,INF); if(j>1) ins(x,x-1,INF); if(i<n) ins(x,i*m+j,INF); if(j<m) ins(x,x+1,INF); } while(bfs())ans-=dfs(S,INF); cout<<ans; return 0; }
最小割。
10.航空计划问题
https://www.oj.swust.edu.cn/problem/show/1746
建图很好想吧..然后就是一个最大费用最大流 输出方案我都要吐血了
#include<iostream> #include<cstdio> #include<cstring> #include<map> #define S 1 #define T n<<1 #define INF 2000000000 using namespace std; 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 * 10 + ch - '0';ch = getchar();} return x * f; } map<string,int> mp; string st[105],x,y; int n,m,cnt=1,d[205],head[205],ans=0,top,tail,q[40005],p,from[5][205],mm=0,tot=1; bool mark[205]; struct edge{ int to,next,w,c; }e[200000]; void ins(int f,int t,int w,int c) { e[++cnt]=(edge){t,head[f],w,c};head[f]=cnt; e[++cnt]=(edge){f,head[t],0,-c};head[t]=cnt; } bool spfa() { for(int i=S;i<=T;i++)d[i]=INF; top=tail=4000;q[top]=S;mark[S]=1;d[S]=0; while(top>=tail) { int u=q[tail++]; for(int i=head[u];i;i=e[i].next) if(e[i].w&&d[u]+e[i].c<d[e[i].to]) { d[e[i].to]=d[u]+e[i].c;from[tot][e[i].to]=i; if(!mark[e[i].to]) { if(d[e[i].to]<d[q[tail]]) q[--tail]=e[i].to; else q[++top]=e[i].to; mark[e[i].to]=1; } } mark[u]=0; } return d[T]!=INF; } void mcf() { int minn=INF; for(int i=from[tot][T];i;i=from[tot][e[i^1].to]) minn=min(minn,e[i].w); for(int i=from[tot][T];i;i=from[tot][e[i^1].to]) { ans+=e[i].c*minn; e[i].w-=minn;e[i^1].w+=minn; } tot+=minn; } void print(int from,int to) { mark[from]=1; for(int i=head[from];i;i=e[i].next) if(!mark[e[i].to]&&((!e[i].w&&e[i].c<=0)||(e[i].w&&e[i].c>=0))) { print(e[i].to,to); if(e[i].to<=n) cout<<st[e[i].to]<<endl; } } int main() { n=read();m=read(); for(int i=1;i<=n;i++) cin>>st[i],mp[st[i]]=i; for(int i=1;i<=m;i++) { cin>>x>>y;int a=mp[x],b=mp[y]; if(a>b) swap(a,b); ins(a+n,b,(a==1&&b==n)?2:1,-1); } ins(1,1+n,2,0); for(int i=2;i<n;i++) ins(i,i+n,1,0); ins(n,T,2,0); while(spfa()) mcf();--tot; if(tot!=2) return 0*puts("No Solution!"); cout<<-ans<<endl;top=0; cout<<st[1]<<endl; print(S,T); cout<<st[1]<<endl; return 0; }
11.星际转移问题
https://www.luogu.org/problem/show?pid=2754
把每个航空站都拆成天数个点,可以二分答案。
#include<iostream> #include<cstdio> #include<cstring> #define S 0 #define T 15002 #define INF 2000000000 #define num(x,y) (x)*n+(y) using namespace std; 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 * 10 + ch - '0';ch = getchar();} return x * f; } int r[25],s[25][50]; int n,m,cnt=1,K,head[T+5],q[T+5],d[T+5],c[T+5],h[25],top=0; struct edge{ int to,next,w; }e[T*120]; void ins(int f,int t,int w) { e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],0};head[t]=cnt; //cout<<"INS"<<f<<" "<<t<<" "<<w<<endl; } int dfs(int x,int f) { if(x==T)return f; int used=0; for(int&i=c[x];i;i=e[i].next) if(e[i].w&&d[e[i].to]==d[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w;e[i].w-=w;e[i^1].w+=w; if(used==f)return f; } return used; } bool bfs() { memset(d,0,sizeof(d));int i,j; for(d[q[top=i=0]=S]=1;i<=top;i++) for(int j=c[q[i]]=head[q[i]];j;j=e[j].next) if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1; //cout<<d[T]<<endl; return d[T]; } void build(int x) { cnt=1;memset(head,0,sizeof(head)); ins(S,n-1,K); for(int i=1;i<=m;i++) for(int j=1;j<=x;j++) ins(num(j-1,s[i][(j-1)%r[i]+1]),num(j,s[i][j%r[i]+1]),h[i]); for(int i=1;i<=x;i++) for(int j=1;j<=n;j++) ins(num(i-1,j),num(i,j),INF); ins(num(x,n),T,INF); } bool check(int x) { int ans=0; while(bfs()) ans+=dfs(S,INF); //cout<<x<<" "<<ans<<endl; return ans==K; } int main() { n=read()+2;m=read();K=read(); for(int i=1;i<=m;i++) { int x;h[i]=read();r[i]=read(); for(int j=1;j<=r[i];j++) s[i][j]=(x=read())==-1?n:x==0?n-1:x; } int l=1,r=1000,ans=0,mid; while(l<=r) { mid=l+r>>1;build(mid); if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } cout<<ans; return 0; }