先边权取负变为最小费用循环流。
然后对于边<u,v,f,c>,如果c>=0,则还是连<u,v,f,c>。
否则建立源点汇点,连<s,v,f,0>,<v,t,f,0>,<v,u,f,-c>,并且ans+=c。
然后ans+最小费用最大流就是答案。
本质类似带下界费用流和最大权闭合子图,先钦定负权边都跑了,然后退最小费用的流使得流量平衡。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db double
#define ull unsigned lint
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int INF=INT_MAX/2-10,N=110,M=100010;const db eps=1e-10;
inline int squ(int x) { return x*x; }
struct edges{
int from,to,pre,resf;db wgt;
}e[M];int h[N],etop,inq[N],fr[N],x[N],y[N],frs[N];db d[N];queue<int> q;vector<int> to[N];
inline int add_edge(int u,int v,int f,db c,int x=0) { return e[x=++etop].from=u,e[x].to=v,e[x].pre=h[u],h[u]=x,e[x].wgt=c,e[x].resf=f; }
inline int build_edge(int u,int v,int f,db c) { return add_edge(u,v,f,c),add_edge(v,u,0,-c); }
inline bool spfa(int s,int t,int n,db &ans)
{
while(!q.empty()) q.pop();
rep(i,1,n) d[i]=INF,inq[i]=0,fr[i]=0;
d[s]=0,q.push(s),inq[s]=1;
while(!q.empty())
{
int x=q.front();q.pop(),inq[x]=0;
for(int i=h[x],y;i;i=e[i].pre)
if(e[i].resf&&d[y=e[i].to]>d[x]+e[i].wgt)
d[y]=d[x]+e[i].wgt,fr[y]=i,(!inq[y]?q.push(y),inq[y]=1:0);
}
if(!fr[t]) return false;int minf=INF;
for(int i=fr[t];i;i=fr[e[i].from])
minf=min(minf,e[i].resf);
for(int i=fr[t];i;i=fr[e[i].from])
e[i].resf-=minf,e[((i-1)^1)+1].resf+=minf;
return ans+=d[t]*minf,true;
}
inline db dinic(int s,int t,int n) { db ans=0.0;while(spfa(s,t,n,ans));return ans; }
int main()
{
// freopen("data.in","r",stdin),freopen("std.out","w",stdout);
for(int n,cas=1;(n=inn());cas++)
{
int X=inn(),Y=inn();
rep(i,1,n)
{
x[i]=inn(),y[i]=inn(),to[i].clear();
for(int t;(t=inn());to[i].pb(t));
}
db ans=0;int s=n+1,t=s+1;
memset(h,0,sizeof(int)*(t+1)),etop=0;
memset(frs,0,sizeof(int)*(t+1));
rep(i,1,n) Rep(j,to[i])
{
int a=i,b=to[i][j];
db d=Y-sqrt(squ(x[a]-x[b])+squ(y[a]-y[b]))*X;
if(d>=0) build_edge(a,b,1,d);
else frs[b]++,frs[a]--,build_edge(b,a,1,-d),ans+=d;
}
rep(i,1,n)
if(frs[i]>0) build_edge(s,i,frs[i],0);
else if(frs[i]<0) build_edge(i,t,-frs[i],0);
ans+=dinic(s,t,t),printf("Case %d: %.2lf\n",cas,double(-ans+eps));
}
return 0;
}