题意:有n头牛,给你m行数字,每行表示奶牛的挤奶顺序,X表示奶牛的挤奶顺序满足1~X行要求,Farmer John想最大化X,让你输出满足条件的字典序最小的一组。
思路:拓扑排序加二分
#include<bits/stdc++.h>
using namespace std;
int n,m,h[100010],to[100010],vis[100010],in[100010],cnt,net[100010];
vector <int>v[100010];
struct node
{
int id;
node(int x):id(x){}
bool operator <(const node &a) const
{
return a.id<id;
}
};
priority_queue<node>q;
void add(int from,int q)
{
cnt++;
to[cnt]=q;
net[cnt]=h[from];
h[from]=cnt;
}
void build(int x)
{
memset(vis,0,sizeof(vis));
memset(h,0,sizeof(h));
memset(in,0,sizeof(in));
cnt=0;
for(int i=1;i<=x;i++)
for(int j=0;j<v[i].size()-1;j++)
{
add(v[i][j],v[i][j+1]);
in[v[i][j+1]]++;
}
}
int topsort(int f)
{
int sum=0;
for(int i=1;i<=n;i++)
{
if(in[i]==0){
q.push(node(i));
vis[i]=1;
sum++;
}
}
while(!q.empty())
{
node now=q.top();
if(f)
printf("%d ",now.id);
q.pop();
for(int j=h[now.id];j;j=net[j])
{
in[to[j]]--;
if(!in[to[j]] && !vis[to[j]])
{
q.push(node(to[j]));
vis[to[j]]=1;
sum++;
}
}
}
return sum==n;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,s;
scanf("%d",&s);
while(s--)
{
scanf("%d",&a);
v[i].push_back(a);
}
}
int l=0,r=m+1,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
build(mid);
if(topsort(0))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
build(ans);
topsort(1);
return 0;
}