题意:
- 带权有向图中,求出一个最小值w,存在改变任意权值小于等于w的有向边方向,使得原图变为有向无环图的方案。并输出改变的边数和边们的编号。
思路
- 二分一个值w,对大于w的边进行拓扑排序,如果无环的话,就减小w
- 最后改变的边的编号就是top[u]>top[v]边
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pb push_back
typedef vector<int> vi;
const int MAXN=1e5+10;
struct Edge{
int u,v,w;
}edge[MAXN];
int n,m,top[MAXN],indec[MAXN];
vi G[MAXN];
bool check(int mid){
int cnt=0;
rep(i,1,n){
G[i].clear();
indec[i]=0;
}
rep(i,1,m){
if(edge[i].w>mid){
G[edge[i].u].pb(edge[i].v);
indec[edge[i].v]++;
}
}
queue<int> que;
rep(i,1,n){
if(indec[i]==0){
que.push(i);
}
}
while(!que.empty()){
int u=que.front();
que.pop();
top[u]=++cnt;
for(auto v:G[u]){
indec[v]--;
if(indec[v]==0){
que.push(v);
}
}
}
return cnt==n;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,m){
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
}
int l=0,r=1e9+10,ans=r;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
printf("%d ",ans);
check(ans);
vi res;
rep(i,1,m){
int u=edge[i].u,v=edge[i].v,w=edge[i].w;
if(w<=ans&&top[u]>top[v]){
res.pb(i);
}
}
printf("%d\n",res.size());
for(auto x:res){
printf("%d ",x);
}
return 0;
}