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
数据保证不存在重边和自环。
来源
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;
}