传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4625
首先这东西很明显可以换成一个二维的图……
具体想怎么换怎么换了,我是X对应x+1,Y对应y-1,Z对应x-1 y+1。
考虑每个点对3取膜的余数,可以发现,在0的点周围的6个点中,只要同时存在1和2的点,那么就会引发共振。
那么考虑,对于每个共振,要用最小代价破坏,很显然的一个网络流模型,把每个点拆点,边权为该点价值。然后源连1的点,1连0,0连2,2连汇,总权值减最大流。
#include<stdio.h>
#include<map>
#define cint const int &
#define inf 233333333
#define N 50005
#define M 100005
using namespace std;
int cnt=1,tot,n,sum,s[M],Q[M],ts,ti[M],lev[M],x[N],y[N],z[N],c[N],s1[5],s2[5],l1,l2,cur[M];
struct edge{int v,c,n;}e[N*20];
inline void push(const int &u,const int &v,const int &c)
{
e[++cnt]=(edge){v,c,s[u]};s[u]=cnt;
e[++cnt]=(edge){u,0,s[v]};s[v]=cnt;
}
inline bool bfs()
{
for (int i=1;i<=tot+1<<1;i++) cur[i]=s[i];
int l=1,r=1;
ti[Q[1]=1]=++ts;
for (;l<=r;l++) for (int i=s[Q[l]];i;i=e[i].n) if (ti[e[i].v]<ts && e[i].c)
ti[Q[++r]=e[i].v]=ts,lev[e[i].v]=lev[Q[l]]+1;
return ti[tot+1<<1]==ts;
}
int dfs(const int &u,const int &c)
{
if (u==tot+1<<1) return c;
int g=0,f=c,tmp;
for (int i=cur[u];i && f;cur[u]=i,i=e[i].n)
if (ti[e[i].v]==ts && lev[e[i].v]==lev[u]+1 && e[i].c && (tmp=dfs(e[i].v,min(f,e[i].c))))
g+=tmp,f-=tmp,e[i].c-=tmp,e[i^1].c+=tmp;
return g;
}
struct poi
{
int x,y;
friend bool operator < (poi a,poi b){return a.x==b.x?a.y<b.y:a.x<b.x;}
friend poi operator + (poi a,poi b){return (poi){a.x+b.x,a.y+b.y};}
}loc[N];
map<poi,int> Map,pt,F,chk;
inline void link(cint p1,cint p2,cint p3)
{
poi k=(poi){1,p1};
if (!chk[k]) push(1,p1*2,inf),chk[k]=1;
k=(poi){p1,p2};
if (!chk[k]) push(p1*2+1,p2*2,inf),chk[k]=1;
k=(poi){p2,p3};
if (!chk[k]) push(p2*2+1,p3*2,inf),chk[k]=1;
k=(poi){p3,tot+1};
if (!chk[k]) push(p3*2+1,tot+1<<1,inf),chk[k]=1;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d%d%d",x+i,y+i,z+i,c+i);
poi now=(poi){x[i]-z[i],z[i]-y[i]};
if (!pt[now]) pt[now]=++tot;
Map[now]+=c[i];
if ((x[i]+y[i]+z[i])%3==0) F[now]=1;
}
for (int i=1;i<=n;i++)
{
poi now=(poi){x[i]-z[i],z[i]-y[i]};
if (F[now]<2)
{
int p=pt[now],add=Map[now]*(10+F[now]);sum+=add;
push(p*2,p*2+1,add);
if (F[now]==0){F[now]=2;continue;}
F[now]=2;l1=l2=0;
if (!(s1[++l1]=pt[now+(poi){0,1}])) l1--;
if (!(s1[++l1]=pt[now+(poi){-1,0}])) l1--;
if (!(s1[++l1]=pt[now+(poi){1,-1}])) l1--;
if (!(s2[++l2]=pt[now+(poi){0,-1}])) l2--;
if (!(s2[++l2]=pt[now+(poi){1,0}])) l2--;
if (!(s2[++l2]=pt[now+(poi){-1,1}])) l2--;
for (int i1=1;i1<=l1;i1++) for (int i2=1;i2<=l2;i2++) link(s1[i1],p,s2[i2]);
}
}
while (bfs()) for (int rt=dfs(1,inf);rt;rt=dfs(1,inf)) sum-=rt;
printf("%.1lf",(double)sum/10+0.0001);
}