题意:
带权有向图中,求出一个最小值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 ;
}