题解 P5814 【[CTSC2001]终极情报网】
xtx1092515503 · · 题解
因为实在太坑人了,就写一篇题解。
首先,本题费用流的模型是很明显的——我军总部连到每个人,两个人之间互相连边,然后每个人再连到敌军总部。
但是,这里的费用却比较非常规——它是路径上所有边的边权的乘积。
若仍然暴力跑费用流的话,可能会出现除零这种奇怪的东西,因此对所有边权取个
需要注意的是,因为这题的边权都是实数,就可能会把 SPFA 可以处理的零环给判成负环,于是在比较大小的时候得手动加一个
同时,注意输出——“保留
代码:
#include<bits/stdc++.h>
using namespace std;
const int inf=-0x3f3f3f3f;
const double eps=1e-8;
const double lim=-100;
int n,m,s;
namespace MCMF{
const int N=310,M=2000000;
int head[N],cnt,fr[N],S,T,flow;
double cost,dis[N];
struct node{
int to,next,val;
double cost;
}edge[M];
void ae(int u,int v,int w,double c){
// printf("%d %d %d %lf\n",u,v,w,c);
edge[cnt].cost=c,edge[cnt].next=head[u],edge[cnt].to=v,edge[cnt].val=w,head[u]=cnt++;
edge[cnt].cost=-c,edge[cnt].next=head[v],edge[cnt].to=u,edge[cnt].val=0,head[v]=cnt++;
}
queue<int>q;
bool in[N];
bool SPFA(){
for(int i=1;i<=T;i++)dis[i]=inf;dis[S]=0,q.push(S),in[S]=true;
while(!q.empty()){
int x=q.front();q.pop(),in[x]=false;
for(int i=head[x];i!=-1;i=edge[i].next){
if(!edge[i].val)continue;
if(dis[edge[i].to]+eps<dis[x]+edge[i].cost){
dis[edge[i].to]=dis[x]+edge[i].cost,fr[edge[i].to]=i;
if(!in[edge[i].to])in[edge[i].to]=true,q.push(edge[i].to);
}
}
}
if(dis[T]<=inf+eps)return false;
int x=T,mn=0x3f3f3f3f;
while(x!=S)mn=min(mn,edge[fr[x]].val),x=edge[fr[x]^1].to;
flow+=mn,cost+=dis[T]*mn,x=T;
while(x!=S)edge[fr[x]].val-=mn,edge[fr[x]^1].val+=mn,x=edge[fr[x]^1].to;
return true;
}
}
using namespace MCMF;
double sft[310];
char str[310];
void roundprint(double x){
sprintf(str,"%.10lf",x);
int len=0,sml=-1;
for(len=0;sml<4;len++)if(str[len]>'0'&&str[len]<='9'||sml!=-1)sml++;
if(str[len]>='5')str[len-1]++;str[len]='\0';
while(str[len-1]!='.'&&str[len-1]>'9')str[len-1]='0',str[len-2]++,len--;
printf("%s\n",str);
}
int main(){
scanf("%d%d",&n,&m),s=n+1,S=n+2,T=n+3,memset(head,-1,sizeof(head)),ae(S,s,m,0);
for(int i=1;i<=n;i++)scanf("%lf",&sft[i]);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
if(sft[i]>eps)ae(s,i,x,log(sft[i]));
else ae(s,i,x,lim);
}
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
if(x)ae(i,T,0x3f3f3f3f,0);
}
while(true){
int x,y,z;double c;
scanf("%d%d",&x,&y);
if(x==-1&&y==-1)break;
scanf("%lf%d",&c,&z);
if(c>eps)ae(x,y,z,log(c)),ae(y,x,z,log(c));
else ae(x,y,z,lim),ae(y,x,z,lim);
}
while(SPFA());
if(flow!=m)puts("0");else roundprint(exp(cost));
return 0;
}