P3199
[HNOI2009]最小圈
然后 0/1 分数规划似乎有点诡异。。。
如果说
然后二分什么的。。。
然后就是把边权修改后判负环即可。。。然后我写的 SPFA 判负环似乎有亿点点慢。。。最后莫名其妙有了 80pts 。最后又只有 20pts 。。。(是数据的锅还是我的锅。。。)后来事实证明出题人刻意卡了 SPFA 但是没有卡 dfs 版的 SPFA (精心构造结果被这样钻空子了。。。)。
然后想写正常的 SPFA 判负环可以作一些玄学优化,比如说把入队次数
关于一些负环的写法在我的博客 P3385 有说明,这里不再概括之类的。
正解似乎就是 Karp 1977年的论文上的结论。。。这里是 rqy 的翻译,以及他(她?)的拓展:The Minimum Cycle Mean in a Digraph 。
这里再写个大略。
求有向强联通图中最小平均权值回路。这里令
那么有如下结论:
然后关于
初始条件为:
然后就是求答案了。
然后这个东西当结论记住大概也是蛮好。。。
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const ll N=3e3,M=1e4,inf=1e12;
ll n,m;
ll u[M+5],v[M+5];
double ans=inf,tmp;
double f[N+5][N+5],w[M+5];
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
if(x<0) {x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+48);
}
int main() {
n=read();m=read();
for(ll i=1;i<=m;i++) {
u[i]=read();v[i]=read();scanf("%lf",&w[i]);
// add(u,v,w);
}
for(ll i=0;i<=n;i++) {
for(ll j=1;j<=n;j++) {
if(!i) f[i][j]=0;
else f[i][j]=inf;
}
}
for(ll k=1;k<=n;k++) {
for(ll i=1;i<=m;i++) {
f[k][v[i]]=min(f[k][v[i]],f[k-1][u[i]]+w[i]);
}
}
for(ll i=1;i<=n;i++) {
if(f[n][i]>=inf) continue;
tmp=-inf;
for(ll k=0;k<=n-1;k++) {
tmp=max(tmp,(f[n][i]-f[k][i])/(n-k));
}
ans=min(ans,tmp);
}
printf("%.8f\n",ans);
return 0;
}
代码(0/1分数规划 20pts ):
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const ll N=3e3,M=1e4;
ll n,m,u,v,flg,tot,h;
double w,l,r,mid;
double f[N+5],wt[M*2+5];
ll ver[M*2+5],nxt[M*2+5],head[N+5],vis[N+5],cnt[N+5];
queue<ll> q;
void spfa(ll s) {
for(ll i=1;i<=n;i++) f[i]=(double)1e12;
f[s]=0;q.push(s);
while(!q.empty()) {
h=q.front();q.pop();vis[h]=0;
for(ll i=head[h];i;i=nxt[i]) {
if(f[ver[i]]>f[h]+wt[i]-mid) {
f[ver[i]]=f[h]+wt[i]-mid;cnt[ver[i]]=cnt[h]+1;
if(cnt[ver[i]]>=n) {
flg=1;break;
}
if(!vis[ver[i]]) {
vis[ver[i]]=1;q.push(ver[i]);
}
}
}
if(flg) break;
}
}
bool check() {
flg=0;
for(ll i=1;i<=n;i++) {
memset(cnt,0,sizeof(cnt));
// memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
spfa(i);
if(flg) break;
// f[i]=(ll)1e12;
}
if(flg) return 0;
return 1;
}
void add(ll u,ll v,double w) {
ver[++tot]=v;wt[tot]=w;
nxt[tot]=head[u];head[u]=tot;
}
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
if(x<0) {x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+48);
}
int main() {
n=read();m=read();
for(ll i=1;i<=m;i++) {
u=read();v=read();scanf("%lf",&w);
add(u,v,w);
}
l=-1e4;r=1e4;
while(r-l>1e-9) {
mid=(l+r)/2;
if(check()) l=mid;
else r=mid;
// printf("mid=%.0f flg=%lld\n",mid,flg);
}
printf("%.8f\n",l);
return 0;
}
代码(0/1 分数规划 100pts):
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
const ll N=3e3,M=1e4;
ll n,m,u,v,flg,tot,h;
double w,l,r,mid;
double f[N+5],wt[M*2+5];
ll ver[M*2+5],nxt[M*2+5],head[N+5],vis[N+5],cnt[N+5];
queue<ll> q;
void dfs(ll s) {
vis[s]=1;
for(ll i=head[s];i;i=nxt[i]) {
if(f[ver[i]]>f[s]+wt[i]-mid) {
f[ver[i]]=f[s]+wt[i]-mid;
if(vis[ver[i]]||flg) {
flg=1;break;
}
dfs(ver[i]);
}
}
vis[s]=0;
}
bool check() {
flg=0;
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
for(ll i=1;i<=n;i++) {
dfs(i);
if(flg) break;
}
if(flg) return 0;
return 1;
}
void add(ll u,ll v,double w) {
ver[++tot]=v;wt[tot]=w;
nxt[tot]=head[u];head[u]=tot;
}
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
if(x<0) {x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+48);
}
int main() {
n=read();m=read();
for(ll i=1;i<=m;i++) {
u=read();v=read();scanf("%lf",&w);
add(u,v,w);
}
l=-1e4;r=1e4;
while(r-l>1e-9) {
mid=(l+r)/2;
if(check()) l=mid;
else r=mid;
// printf("mid=%.0f flg=%lld\n",mid,flg);
}
printf("%.8f\n",l);
return 0;
}