analysis
首先要理解题目中的那个"圈"的含义
这个圈不是强连通分量!这就说明这个题和scc或tarjan没什么关系
因为他说的是:c=(c1,c2,⋯ ,ck)(ci∈V)c=(c_1,c_2,\cdots,c_k)(c_i\in V)c=(c1,c2,⋯,ck)(ci∈V)是GGG中的一个圈当且仅当(ci,ci+1)(1≤i<k)(c_i,c_{i+1})(1\le i<k)(ci,ci+1)(1≤i<k)和(ck,c1)(c_k,c_1)(ck,c1)都在EEE中,也就是说,只要在E中…
等等,这个E是边集的意思啊,也就是说如果cic_ici和cjc_jcj要在一个圈里面,必须顺次连接,那不就是环嘛!!,一开始还分析错了
然后就是这个答案,要求的是μ′(c)=Min(μ(c))\mu'(c)=Min(\mu(c))μ′(c)=Min(μ(c)),也就是最小的∑i=1kwci,ci+1k\frac{\sum\limits_{i=1}^{k}w_{c_i,c_{i+1}}}{k}ki=1∑kwci,ci+1
诶想到一个变形,上面这个式子可以变成这样子:∑i=1kwci,ci+1∑i=1kzi(zi=1)\frac{\sum\limits_{i=1}^{k}w_{c_i,c_{i+1}}}{\sum\limits_{i=1}^{k}z_i}(z_i=1)i=1∑kzii=1∑kwci,ci+1(zi=1)
即:∑i=1kxi×wci,ci+1∑i=1kxi×zi(zi=1)\frac{\sum\limits_{i=1}^{k}x_i\times w_{c_i,c_{i+1}}}{\sum\limits_{i=1}^{k}x_i\times z_i}(z_i=1)i=1∑kxi×zii=1∑kxi×wci,ci+1(zi=1)
这个式子好生熟悉,不就是01分数规划哇
设f(xi)=∑i=1kxi×wci,ci+1∑i=1kxi×zi(zi=1)f(x_i)=\frac{\sum\limits_{i=1}^{k}x_i\times w_{c_i,c_{i+1}}}{\sum\limits_{i=1}^{k}x_i\times z_i}(z_i=1)f(xi)=i=1∑kxi×zii=1∑kxi×wci,ci+1(zi=1)
假设有一个组解满足f(xi)<Lf(x_i)<Lf(xi)<L
则∑i=1kxi×wci,ci+1∑i=1kxi×zi<L\frac{\sum\limits_{i=1}^{k}x_i\times w_{c_i,c_{i+1}}}{\sum\limits_{i=1}^{k}x_i\times z_i}<Li=1∑kxi×zii=1∑kxi×wci,ci+1<L
∑i=1kxi×wci,ci+1<∑i=1kL×xi×zi{\sum\limits_{i=1}^{k}x_i\times w_{c_i,c_{i+1}}}<{\sum\limits_{i=1}^{k}L\times x_i\times z_i}i=1∑kxi×wci,ci+1<i=1∑kL×xi×zi
∑i=1k(xi×wci,ci+1−L×xi×zi)<0{\sum\limits_{i=1}^{k}(x_i\times w_{c_i,c_{i+1}}-L\times x_i\times z_i)}<0i=1∑k(xi×wci,ci+1−L×xi×zi)<0
即如果存在一组解使得图中存在负环,那么当前的二分值就不是最小的
这下就是判负环了对吧
code
#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define ll long long
template<typename T>void read(T &x){
x=0;char r=getchar();T neg=1;
while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
x*=neg;
}
const int maxn=3000+10;
const int maxm=10000+10;
int n,m,cnt=0;
struct node{
int e;
double w;
int nxt;
}edge[maxm];
int head[maxn];
inline void addl(int u,int v,double w){
edge[cnt].e=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
bool flag=false;
bool insta[maxn];
bool vis[maxn];
double dis[maxn];
void spfa(int u,double L){
insta[u]=true;
for(int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].e;
if(dis[v]>dis[u]+edge[i].w-L){
dis[v]=dis[u]+edge[i].w-L;
if(insta[v]||flag){
flag=true;
return;
}
vis[v]=true;
spfa(v,L);
}
}
insta[u]=false;
}
void bin(){
double L=-1e7,R=1e7,eps=1e-10;
while(R-L>eps){
double mid=(L+R)/2;
//loop(i,1,n)dis[i]=1e9;
clean(dis,0);
clean(vis,false);
clean(insta,false);
loop(i,1,n){
if(!vis[i]){
vis[i]=1;
flag=false;
spfa(i,mid);
if(flag){
R=mid;
break;
}
}
}
if(!flag)L=mid;
}
printf("%.8lf\n",L);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("datain.txt","r",stdin);
#endif
clean(head,-1);
read(n);read(m);
loop(i,1,m){
int ai,bi;
double wi;
read(ai);
read(bi);
scanf("%lf",&wi);
addl(ai,bi,wi);
}
bin();
return 0;
}