• [bzoj4625][BeiJing2016]水晶


    来自FallDream的博客,未经允许,请勿转载,谢谢。


     不用惊慌,今天的题都不是小强出的。——融入了无数心血的作品,现在却不得不亲手毁掉,难以体会他的心情啊

    。——那也是没有办法的事情,能量共振不消除的话……望着已经被装上炸*药的水晶,02放下了望远镜,看向了手
    中的共振分析报告。还是会有一些水晶,幸存下来的……也许吧。地图由密铺的六边形单元组成,每个单元与其他
    六个单元相邻。为了方便起见,我们用坐标(x,y,z)描述一个单元的位置,表示从原点开始按如图所示的x,y,z方向
    各走若干步之后到达的地方。有可能有两个坐标描述同一个单元,比如(1,1,1)和(0,0,0)描述的都是原点
    显然(x,y,z)单元和(x+1, y,z),(x-1,y,z),(x,y+1,z),(x,y-1,z),(x, y, z+1),(x,y, z-1)相邻。有N块水晶
    位于地图的单元内,第i块水晶位于坐标(xi, yi, zi)所表示的单元中,并拥有ci的价值。每个单元内部可能会有
    多块水晶。地图中,有一些单元安装有能量源。如下图,任何满足x+y+z是3的整数倍的坐标所描述的单元内都安装
    有能量源。
     
    有能量源的单元中的水晶价值将会额外增加10%.如果三块水晶所在的单元满足特定排列,那么它们将会引发共振。
    共振分两种,a共振和b共振。a共振:如果三块水晶所在的单元两两相邻地排成一个三角形,那么会引起a共振。
    图中每一个三角形表示这三个单元各有一块水晶将会发生一个a共振。b共振:如果三块水晶所在的单元依次相邻地
    排成一条长度为2的直线段,且正中间的单元恰好有能量源,那么会引起b共振。
     
    图中粉红色线段表示这三个单元各有一块水晶将会发生一个b共振,黑色线段表示即使这三个单元有水晶也不会发
    生b共振。现在你要炸掉一部分水晶,使得任何共振都不会发生的前提下,剩余水晶的价值总和最大。
    n<=50000
     
    考虑染成三种颜色,发现构成一个三分图,然后最小割就可以了。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #define num(x,y) ((x+2000)*4000+y+2000)
    #define S 0
    #define T 100001
    #define INF 2000000000
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    bool mark[T+5];map<int,int> mp;
    int cnt=1,q[T+5],top,n,d[T+5],c[T+5],head[T+5],ans=0;
    struct crystal{int x,y,z,c;}s[T+5];
    struct edge{int to,next,w;}e[T*20+5];
    inline void ins(int f,int t,int w)
    {
        if(!t) return;
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],0};head[t]=cnt;    
    }
    
    bool Ins(crystal a,int id)
    {
        int ha=num(a.x,a.y);
        if(mp[ha]) return s[mp[ha]].c+=a.c,1;
        else return 0*(mp[ha]=id);
    }
    
    int dfs(int x,int f)
    {
        if(x==T) return f;int used=0;
        for(int&i=c[x];i;i=e[i].next) 
            if(e[i].w&&d[e[i].to]==d[x]+1)
            {
                int w=dfs(e[i].to,min(e[i].w,f-used));
                used+=w;e[i].w-=w;e[i^1].w+=w;
                if(used==f) return used;    
            }
        return d[x]=-1,used;
    }        
    
    bool bfs()
    {
        memset(d,0,sizeof(d));int i,j;
        for(d[q[top=i=1]=S]=1;i<=top;++i)    
            for(int j=c[q[i]]=head[q[i]];j;j=e[j].next)
                if(e[j].w&&!d[e[j].to])
                    d[q[++top]=e[j].to]=d[q[i]]+1;
        return d[T];
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i) 
        {
            s[i].x=read(),s[i].y=read(),s[i].z=read();s[i].c=read()*10;
            s[i].x-=s[i].z;s[i].y-=s[i].z;s[i].z=0;
            if((s[i].x+s[i].y)%3==0) s[i].c+=s[i].c/10;
            if(Ins(s[i],i)) mark[i]=1;ans+=s[i].c;
        }
        for(int i=1;i<=n;++i) if(!mark[i]) 
        {
            ins(i,i+n,s[i].c);
            if((s[i].x+s[i].y+30000)%3==2) ins(S,i,INF);
            if((s[i].x+s[i].y+30000)%3!=1)
            {
                ins(i+n,mp[num(s[i].x,s[i].y+1)],INF);
                ins(i+n,mp[num(s[i].x+1,s[i].y)],INF);
                ins(i+n,mp[num(s[i].x-1,s[i].y-1)],INF);
            }
            else ins(i+n,T,INF);
        }
        while(bfs()) ans-=dfs(S,INF);
        printf("%.1lf",(double)ans/10);
        return 0;
    }
  • 相关阅读:
    [转]scp用法
    进入docker登录psql数据库对特定表进行操作
    [整]swp文件的处理
    shift+zz保存并退出
    [转]python变量作用域的有趣差别
    git 删除分支操作
    混用参数命名方式,确保顺序在命名之前
    [译]Python面试中8个必考问题
    《浪潮之巅》与我的职业选择
    EBS 用户及其联系人的失效时间
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4625.html
Copyright © 2020-2023  润新知