circle

circle

题目描述

 

小w 的男朋友送给小w 一个nn个点mm条边的图,并且刁难小w 要她找出点数最少的正环。

小w 不会做,于是向你求助。

 

输入

 

第一行两个整数n,mn,m。

接下来mm行,每行四个数u,v,a,bu,v,a,b,表示从uu走到vv的代价为aa,从vv走到uu的代价为bb(算作两条不同的边)。注意a,ba,b可能为负。

 

输出

 

当图中包含正环时,输出点数最少的正环(简单环)的点数。

否则输出0。

 

样例输入

3 3
1 2 2 -1
2 3 10 -10
3 1 10 -10

样例输出

2

提示

 

对于前20%20%的数据,n≤7,m≤10

对于前60%60%的数据,n≤150,m≤2000

对于100%100%的数据,1≤n≤300,0≤m≤n(n−1)2,|a|,|b|≤104

数据保证不存在重边和自环。

 

来源

2018年10月hnsdfz集训


solution

原题似乎是cf 上的

令f[k][i][j]表示走2^k 步,i到j的最大距离

用就像floyd那样 矩阵倍增实现,条件为取max

如果2^k步是合法的,那么必有一个i满足f[k][i][i]>0

就像求lca那样按k从大到小往上跳

就是从大到小枚举k 如果f[k]*ans不合法,那就乘进答案

这样找到最小的步数

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 305
#define inf 1e9
using namespace std;
int n,m,t1,t2,v1,v2;
struct node{
    int v[maxn][maxn];
}f[9];
node ch(node a,node b){
    node c;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++){
        c.v[i][j]=-inf;
        for(int k=1;k<=n;k++){
            c.v[i][j]=max(c.v[i][j],a.v[i][k]+b.v[k][j]);
        }
    }
    return c;
}
int main()
{
    cin>>n>>m;
    for(int k=0;k<=8;k++)
    for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)f[k].v[i][j]=f[k].v[j][i]=-inf;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&t1,&t2,&v1,&v2);
        f[0].v[t1][t2]=max(f[0].v[t1][t2],v1);
        f[0].v[t2][t1]=max(f[0].v[t2][t1],v2);
    }
    for(int i=1;i<=8;i++)f[i]=ch(f[i-1],f[i-1]);
    node ans,now;int bs=0,flag=0;
    for(int i=8;i>=0;i--){
        if(flag)now=ch(ans,f[i]);
        else now=f[i];
        bool fl=0;
        for(int a=1;a<=n;a++){
            if(now.v[a][a]>0)fl=1;
        }
        if(!fl){bs+=(1<<i);ans=now;flag=1;}
    }
    if(bs+1==512)puts("0");
    else cout<<bs+1<<endl;
    return 0;
}
 
原文地址:https://www.cnblogs.com/liankewei/p/10358814.html