#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define pb push_back
#define mp make_pair
#define f1 first
#define f2 second
using namespace std;
const int MAXN=110, inf=0x3f3f3f3f;
struct ISAP
{
struct Edge
{
int from,to,cap,flow,low,real;
Edge(){}
Edge(int a,int b,int c,int d,int e,int f):from(a),to(b),cap(c),flow(d),low(e),real(f){}
};
int n,m,s,t,ss,tt,lowtot;//结点数,边数(含反向弧),源点,汇点
vector<Edge> edges;//边表,edges[e]&edges[e^1]互为反向弧
vector<int> G[MAXN];//邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[MAXN];//BFS使用
int d[MAXN];//从起点到i的距离
int cur[MAXN];//当前弧下标
int p[MAXN];//可增广路上的上一条弧
int num[MAXN];//距离标号计数
void AddEdge(int from,int to,int cap,int low)//重边不影响
{ //printf("%d %d %d\n",from,to,cap);
edges.push_back(Edge(from,to,cap,0,low,1));
edges.push_back(Edge(to,from,0,0,low,0));//容量为0,表示反向弧
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
void add(int from,int to,int low,int ma)
{ lowtot+=low;
if (low==0) {AddEdge(from,to,ma,0);return;}
AddEdge(ss,to,low,0);
AddEdge(from,to,ma-low,low);
AddEdge(from,tt,low,0);
}
void init(int n)
{
this->n=n;ss=n-2;tt=n-1;
for(int i=0;i<n;++i) G[i].clear();
edges.clear();lowtot=0;
}
void BFS()//反向
{
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(t);
d[t]=0;
vis[t]=1;
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=0; i<G[x].size(); ++i)
{
Edge& e=edges[G[x][i]^1];
if(!vis[e.from]&&e.cap>e.flow)
{
vis[e.from]=1;
d[e.from]=d[x]+1;
Q.push(e.from);
}
}
}
}
int Augment()
{
int x=t,a=inf;
while(x!=s)
{
Edge& e=edges[p[x]];
a=min(a,e.cap-e.flow);
x=edges[p[x]].from;
}
x=t;
while(x!=s)
{
edges[p[x]].flow+=a;
edges[p[x]^1].flow-=a;
x=edges[p[x]].from;
}
return a;
}
int Maxflow(int s,int t)//结点数
{
this->s=s,this->t=t;
int flow=0;
for (int i=0;i<n;i++)
d[i]=0; //!!!
memset(num,0,sizeof(num));
for(int i=0;i<n;++i) ++num[d[i]];//!!!
int x=s;
memset(cur,0,sizeof(cur));
while(d[s]<n)
{
if(x==t)
{
flow+=Augment();
x=s;
}
int ok=0;
for(int i=cur[x];i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(e.cap>e.flow&&d[x]==d[e.to]+1)//Advance
{
ok=1;
p[e.to]=G[x][i];
cur[x]=i;
x=e.to;
break;
}
}
if(!ok)//Retreat
{
int m=n-1;
for(int i=0;i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(e.cap>e.flow) m=min(m,d[e.to]);
}
if(--num[d[x]]==0) break;//gap优化
num[d[x]=m+1]++;
cur[x]=0;
if(x!=s) x=edges[p[x]].from;
}
}
return flow;
}
vector<int> anss;
void dfs(int x)
{ anss.pb(x);
for(int i=0;i<G[x].size();++i)
{ Edge& e=edges[G[x][i]];
if (e.real&&e.low)
if (edges[G[x][i]-2].flow&&edges[G[x][i]+2].flow)
{
edges[G[x][i]-2].flow--;
edges[G[x][i]+2].flow--;
dfs(e.to);
break;
}
}
}
void solve(int left)
{ int size=edges.size();
int id=0;
for (int i=0;i<size;i++)
if (edges[i].real&&edges[i].low&&edges[i].flow)
{edges[i-2].flow+= edges[i].flow;
edges[i+2].flow+= edges[i].flow;
}
for (int i=0;i<size;i++)
if (edges[i].from==0&&edges[i].real)
for (int j=0;j<edges[i].flow;j++)
{
anss.clear();left--;
dfs(edges[i].to);
int anssize=anss.size();
for (int ii=0;ii<anssize;ii++)
printf("%d%c",anss[ii],(ii==anssize-1)?'\n':' ');
}
}
}it;
vector<pair<int,int > > aa;
int n,pp;
int ok(int mid,int ff=0)
{ int s=0,t=n+1;
it.init(t+3);
for (int i=1;i<=n;i++)
{it.AddEdge(s,i,inf,0);
it.AddEdge(i,t,inf,0);
}
it.AddEdge(t,s,mid,0);
for (int i=0;i<pp;i++)
it.add(aa[i].f1,aa[i].f2,1,inf);
int ans=it.Maxflow(t+1,t+2);
if (!ff)return ans>=it.lowtot; else return ans;
}
void doit()
{
aa.clear();
for (int i=1,x,y;i<=n;i++)
{scanf("%d",&x);
while (x--)
{ scanf("%d",&y);
aa.pb(mp(i,y));
}
}
pp=aa.size();
int l=1,r=pp,mid,day; //r一开始为n,被自己2跪了
while (r>=l)
{
mid=(l+r)>>1;
if (ok(mid,0)) {day=mid; r=mid-1;}
else l=mid+1;
}
printf("%d\n",day);
int ans=ok(day,1);
// printf("flow=%d\n",ans);
it.solve(day);
}
int main()
{
while(scanf("%d",&n)!=EOF)doit();
return 0;
}
/*
6
1 3
1 3
1 4
2 5 6
0
0
*/
LA 4597 网络流【有上下界】
最新推荐文章于 2020-06-01 09:31:30 发布