联考20200523 T3 秘密行动
分析:
真是又臭又长的题面,读半天才读懂。。。
本质是一个数包含一个质因数与否对应一个代价,两个数包含某质因数状态不同对应一个代价
把10个质因数对应进n个数,拆分成10n个独立的元素,建立网络流模型
每个元素归属某个集合有一个代价,某两个元素归属不同集合也有一个代价
经典的最小割模型
可问题是求积最小,最小割是和最小
将代价取对数,积最小就变成和最小了(划重点)
跑最小割就好了,答案求幂输出就好了,卡卡精度
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#define maxn 2005
#define maxm 50005
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
inline int getint()
{
int num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,S,T;
int fir[maxn],tp[maxn],nxt[maxm],to[maxm],cnt;
long double cap[maxm],Fs[maxn];
long double ans;
int h[maxn];
inline void newnode(int u,int v,long double w)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,cap[cnt]=w;}
inline void insert(int u,int v,long double w)
{newnode(u,v,w),newnode(v,u,0);}
inline bool bfs()
{
memset(h,-1,sizeof h);
queue<int>Q;h[S]=0,Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=fir[u];i;i=nxt[i])
if(cap[i]>eps&&!~h[to[i]])h[to[i]]=h[u]+1,Q.push(to[i]);
}
return ~h[T];
}
inline long double dfs(int u,long double flow)
{
if(u==T)return flow;
long double used=0;
for(int &i=tp[u];i;i=nxt[i])
if(cap[i]>eps&&h[to[i]]==h[u]+1)
{
long double w=flow-used;
w=dfs(to[i],min(cap[i],w));
cap[i]-=w,cap[i^1]+=w,used+=w;
if(flow-used<eps)return flow;
}
if(used<eps)h[u]=-1;
return used;
}
inline void dinic()
{while(bfs())memcpy(tp,fir,sizeof fir),ans+=dfs(S,INF);}
int main()
{
n=getint(),m=getint();S=10*n+1,T=S+1;cnt=1;
for(int i=1;i<=10;i++)
{
getint(),cin>>Fs[i];
Fs[i]=log(Fs[i]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=10;j++)
{
long double x;cin>>x;
insert(S,i*10+j-10,log(x));
}
for(int j=1;j<=10;j++)
{
long double x;cin>>x;
insert(i*10+j-10,T,log(x));
}
}
for(int i=1;i<=m;i++)
{
int u=getint(),v=getint(),w=getint();
insert(u*10+w-10,v*10+w-10,Fs[w]),insert(v*10+w-10,u*10+w-10,Fs[w]);
}
dinic();
printf("%.8lf\n",double(exp(ans)));
}