题目大意:
给定一个DAG图,一次操作可以沿着DAG图的方向遍历所有能够到达的边,要求把所有的边都遍历完毕,每一条边可以遍历多次,求最小操作次数。
思路:
乍一看好像是一个模型?为什么感觉和之间做的最小链覆盖很像?然后打了一会之后才发现最小链覆盖是在点上面的,而这一道题目是覆盖边,然后那个模型就没有办法用了。
让我们来科学理性地建立模型,即每一个边都至少要遍历一次。假设从
一直走到
可以一次做完的话,那么就可看做是一条从
到
的流量为1的一条流。这么转化过来之后我们要求的似乎就是每一条边满足1的下界的全图的最小流,每一个点都向源汇点
连边,这个时候只要套最小流的板子就好了。
最小流的做法是借用了循环流的方法,既然我们是要在DAG上面求最小流量,那么只要从 连一条边,跑完循环流之后 这条边的流量就是全图的流量。有一个地方需要注意的是,这样跑出来的不一定是最小流,虽然在循环流中它的流量最少,但是一旦某一条流量多余地经过了一些边,按照这种方法计算的流量则变大了,所以最后还要再反向跑一次最大流来推流,最后相减即可。
/*=============================
* Author : ylsoi
* Problem : bzoj2502
* Algorithm : Min_Flow
* Time : 2018.7.29
* ==========================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj2502.in","r",stdin);
freopen("bzoj2502.out","w",stdout);
}
const int maxn=100+10;
const int maxm=1e4+10;
const int inf=0x3f3f3f3f;
int n,m,a[maxn],ans,s,t,ss,tt,sumf;
int cnte=1,beg[maxn],to[maxm<<1],las[maxm<<1],flow[maxm<<1];
void add(int u,int v,int f){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; flow[cnte]=f;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; flow[cnte]=0;
}
struct dinic{
int num[maxn],cur[maxn];
queue<int>qu;
bool bfs(){
memset(num,0,sizeof(num));
num[ss]=1; qu.push(ss);
while(qu.size()){
int u=qu.front(); qu.pop();
for(int i=beg[u];i;i=las[i]){
if(!flow[i] || num[to[i]])continue;
num[to[i]]=num[u]+1;
qu.push(to[i]);
}
}
return num[tt]!=0;
}
int dfs(int u,int res){
if(u==tt || !res)return res;
int ret=0,f;
for(int &i=cur[u];i;i=las[i]){
if(num[to[i]]!=num[u]+1)continue;
if((f=dfs(to[i],min(res,flow[i])))){
res-=f;
ret+=f;
flow[i]-=f;
flow[i^1]+=f;
}
if(!res)break;
}
return ret;
}
void work(){
while(bfs()){
REP(i,ss,tt)cur[i]=beg[i];
sumf+=dfs(ss,inf);
}
}
}T;
int main(){
File();
scanf("%d",&n);
s=n+1; t=n+2;
ss=0; tt=n+3;
REP(i,1,n){
int siz,v;
scanf("%d",&siz);
m+=siz;
REP(j,1,siz){
scanf("%d",&v);
--a[i]; ++a[v];
add(i,v,inf);
}
}
REP(i,1,n)add(s,i,inf),add(i,t,inf);
REP(i,1,n)if(a[i]>0)add(ss,i,a[i]);
else add(i,tt,-a[i]);
add(t,s,inf);
T.work(); sumf=0;
ans=flow[cnte];
beg[ss]=0; beg[tt]=0;
REP(i,1,n)beg[i]=las[beg[i]];
beg[s]=las[beg[s]]; beg[t]=las[beg[t]];
add(ss,t,inf); add(s,tt,inf);
T.work();
printf("%d\n",ans-sumf);
return 0;
}