题意要求最低的智商数,最低的智商数肯定是由先修课关系中的环决定的,非环结构可直接从开头学到结尾,环结构则需要一定智商才能学。
开始想着用tarjan算法直接找环判断,后来发现无法实现,变化太多,分情况考虑太复杂。
后来发现,直接二分枚举智商值,然后将低于智商值的边直接去掉,因为低于智商值肯定能直接学习,然后判断在当前智商值下有没有环存在,有则证明当前智商值无法保证学完所有课程,没有则证明当前智商值能学完所有课程,依次二分枚举找到最优解即可。
附代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
int head[10010];
struct node
{
int to;
int v;
int next;
} pp[10010];
int mark[10010];
int mm[10010];
int ins[10010];
int n,m;
int dfs(int cur)
{
mark[cur]=1;
if (ins[cur]==1)
return 0;
int pcur=cur;
ins[pcur]=1;
cur=head[cur];
int p=1;
while (cur!=-1)
{
if (mm[cur]==0)
{
cur=pp[cur].next;
continue ;
}
int t=pp[cur].to;
p=dfs(t);
cur=pp[cur].next;
if (p==0)
break;
}
ins[pcur]=0;
return p;
}
int check(int v)
{
for (int i=1;i<=m;i++)
{
if (pp[i].v<=v)
mm[i]=0;
else
mm[i]=1;
}
for (int i=1;i<=n;i++)
{
if (mark[i]==0)
{
int p=dfs(i);
if (p==0)
return 0;
}
}
return 1;
}
int main()
{
int T;
cin>>T;
while (T--)
{
cin>>n>>m;
memset(head,-1,sizeof(head));
memset(ins,0,sizeof(ins));
for (int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
pp[i].to=b;
pp[i].v=c;
pp[i].next=head[a];
head[a]=i;
}
int l=0;
int h=1000000000;
while (l<=h)
{
int mid=(l+h)>>1;
memset(mark,0,sizeof(mark));
int p=check(mid);
if (p==1)
h=mid-1;
else
l=mid+1;
//cout<<l<<" "<<h<<endl;
}
cout<<l<<endl;
}
}