题目链接: http://codeforces.com/group/NVaJtLaLjS/contest/238202/problem/B
题意: n头牛,给出m个若干头牛的挤奶顺序,尽可能满足多的所给的前m个挤奶顺序,输出字典序最小的方案
思路: 此题考察二分加拓扑排序判环,以及要求输出最小字典序,我们可以先进行二分,判断最大能取前多少个挤奶顺序,判断条件用拓扑排序判断是否存在环,找到最大顺序的数量后,再用优先队列队列优化的拓扑排序进行输出最小字典序
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<int>g[maxn];
int head[maxn],in[maxn];
struct node
{
int v,nxt;
}edge[maxn*2];
int tot,n,m;
void add(int u,int v)
{
edge[tot].v=v;
edge[tot].nxt=head[u];
head[u]=tot++;
}
int topo_sort()
{
queue<int>que;
for(int i=1;i<=n;i++)
{
if(in[i]==0)
que.push(i);
}
int cnt=0;
while(que.size())
{
int t=que.front();
cnt++;
que.pop();
for(int i=head[t];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
in[v]--;
if(in[v]==0)
que.push(v);
}
}
if(cnt==n)
return 1;
return 0;
}
int check(int mid)
{
memset(head,-1,sizeof head);
memset(in,0,sizeof in);
tot=0;
for(int i=1;i<=mid;i++)
for(int j=1;j<g[i].size();j++)
{
add(g[i][j-1],g[i][j]);
in[g[i][j]]++;
}
if(topo_sort())
return 1;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
int num,tmp;
for(int i=1;i<=m;i++)
{
scanf("%d",&num);
for(int j=1;j<=num;j++){
scanf("%d",&tmp);
g[i].push_back(tmp);
}
}
int l=1,r=m,ans=0;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
l=mid+1,ans=mid;
else
r=mid-1;
}
memset(head,-1,sizeof head);
memset(in,0,sizeof in);
priority_queue<int,vector<int>,greater<int> >q;
for(int i=1;i<=ans;i++)
for(int j=1;j<g[i].size();j++)
{
add(g[i][j-1],g[i][j]);
in[g[i][j]]++;
}
for(int i=1;i<=n;i++)
{
if(in[i]==0)
q.push(i);
}
while(q.size())
{
int tmp1=q.top();
printf("%d ",tmp1);
q.pop();
for(int i=head[tmp1];i!=-1;i=edge[i].nxt)
{
int t=edge[i].v;
in[t]--;
if(in[t]==0)
q.push(t);
}
}
printf("\n");
return 0;
}