题意:给出一个有向图,每条边有一个权值和时间花费。如果图中无环,输出0,如果有环,找出一个最大的环,最大的意思是环上的权和 / 时间和 最大。
如果存在负环,那么就是原式 tot(time)*k - tot(cost) < 0 成立,找到了一个解,那么就可以试着把k调大,因为我们要tot(cost) / tot(time) 最大,这样就是一个二分答案的过程
const int maxn = 58 ;
int m , n ;
struct Edge{
int u , v ;
double c , t ;
void read(){
scanf("%d%d%lf%lf" , &u , &v , &c ,&t) ;
}
}e[maxn * maxn] ;
const double inf = 1e10 ;
const double eps = 1e-10 ;
vector< pair<int , double> > lis[maxn] ;
double dist[maxn] ;
int father[maxn] ;
bool in[maxn] ;
int cnt[maxn] ;
int judge(double x){
int i , j ;
for(i = 1 ; i <= n ; i++) lis[i].clear() ;
for(i = 1 ; i <= m ; i++)
lis[e[i].u].push_back(make_pair(e[i].v , -e[i].c + x*e[i].t)) ;
for(i = 1 ; i <= n ; i++) dist[i] = inf ;
memset(in , 0 , sizeof(in)) ;
memset(cnt , 0 , sizeof(cnt)) ;
dist[1] = 0 ;
in[1] = 1 ;
cnt[1] = 1 ;
queue<int> q ;
q.push(1) ;
father[1] = 0 ;
while(! q.empty()){
int u = q.front() ;
q.pop() ;
in[u] = 0 ;
if(cnt[u] > n) return u ;
for(i = 0 ; i < lis[u].size() ; i++){
int v = lis[u][i].first ;
double w = lis[u][i].second ;
if(dist[u] + w < dist[v]){
dist[v] = dist[u] + w ;
father[v] = u ;
if(! in[v]){
cnt[v]++ ;
in[v] = 1 ;
q.push(v) ;
}
}
}
}
return 0 ;
}
int main(){
int i , j ;
while(cin>>n>>m){
for(i = 1 ; i <= m ; i++) e[i].read() ;
double l , r , mid , s ;
l = 0 , r = inf ;
while(l + eps < r){
mid = (l + r) * 0.5 ;
if(judge(mid) > 0){
s = mid ;
l = mid ;
}
else r = mid ;
}
int u = judge(s) ;
if(u == 0){ puts("0") ; continue ;}
memset(cnt , 0 , sizeof(cnt)) ;
vector<int> ans ; ans.clear() ;
while(cnt[u] <= 1){
cnt[u]++ ;
if(cnt[u] == 2) ans.push_back(u) ;
u = father[u] ;
}
printf("%d\n" , ans.size()) ;
printf("%d" , ans[ans.size()-1]) ;
for(i = ans.size() -2 ; i >= 0 ; i--) printf(" %d",ans[i]) ;
puts("") ;
}
return 0 ;
}