BZOJ 2502: 清理雪道
题目大意:
求最少的链能覆盖一个DAG,可以重复。
题解:
比较显然的上下界最小流,其实没有上界。
代码:
#include<cstdio> #include<algorithm> using namespace std; int cnt,n,S,T,SS,TT,d[1000005],q[1000005],cur[1000005],last[1000005],h[1000005]; struct node{ int to,next,cap; }e[1000005]; void add(int a,int b,int c){ e[++cnt].to=b; e[cnt].cap=c; e[cnt].next=last[a]; last[a]=cnt; } void ADD(int a,int b,int c){ add(a,b,c); add(b,a,0); } void build(int a,int b,int minn,int maxx){ ADD(a,b,maxx-minn); d[a]-=minn; d[b]+=minn; } int bfs(int S,int T){ for (int i=1; i<=n+4; i++) h[i]=-1; h[S]=0; int head=0,tail=1; q[tail]=S; while (head<tail){ int x=q[++head]; for (int i=last[x]; i; i=e[i].next){ int V=e[i].to; if (e[i].cap && h[V]==-1){ h[V]=h[x]+1; q[++tail]=V; } } } return h[T]!=-1; } int dfs(int x,int T,int low){ if (x==T) return low; int used=0; for (int i=cur[x]; i; i=e[i].next){ int V=e[i].to; if (e[i].cap && h[V]==h[x]+1){ int w=dfs(V,T,min(e[i].cap,low-used)); e[i].cap-=w; e[i^1].cap+=w; cur[x]=i; used+=w; if (used==low) return low; } } if (!used) h[x]=-1; return used; } int dinic(int S,int T){ int ans=0; while (bfs(S,T)){ for (int i=1; i<=n+4; i++) cur[i]=last[i]; ans+=dfs(S,T,1e9); } return ans; } int main(){ cnt=1; scanf("%d",&n); int S=n+1,T=n+2,SS=n+3,TT=n+4; for (int x=1; x<=n; x++){ int len; scanf("%d",&len); for (int i=1; i<=len; i++){ int y; scanf("%d",&y); build(x,y,1,1e6); } } for (int i=1; i<=n; i++){ build(S,i,0,1e6); build(i,T,0,1e6); } for (int i=1; i<=T; i++){ if (d[i]>0) ADD(SS,i,d[i]); else ADD(i,TT,-d[i]); } ADD(T,S,1e6); dinic(SS,TT); int ans=e[cnt].cap; e[cnt].cap=e[cnt-1].cap=0; printf("%d\n",ans-dinic(T,S)); return 0; }