[bzoj4823][洛谷P3756][Cqoi2017]老C的方块

Description

老 C 是个程序员。

作为一个懒惰的程序员,老 C 经常在电脑上玩方块游戏消磨时间。游戏被限定在一个由小方格排成的R行C列网格上

,如果两个小方格有公共的边,就称它们是相邻的,而且有些相邻的小方格之间的公共边比较特殊。特殊的公共边排

列得有很强的规律。首先规定,第1行的前两个小方格之间的边是特殊边。然后,特殊边在水平方向上每4个小方格为

一个周期,在竖直方向上每2个小方格为一个周期。所有的奇数列与下一列之间都有特殊边,且所在行的编号从左到

右奇偶交替。下图所示是一个R = C = 8的网格,蓝色标注的边是特殊边。首先,在第1行,第1列和第2列之间有一条

特殊边。因为竖直方向周期为2,所以所有的奇数行,第1列和第2列之间都有特殊边。因为水平方向周期为4,所以所

有奇数行的第5列和第6列之间也有特殊边,如果网格足够大,所有奇数行的第9列和第10列、第13列和第14列之间都

有特殊边。因为所有的奇数列和下一列之间都有特殊边,所以第3列和第4列、第7列和第8列之间也有特殊边,而所在

行的编号从左到右奇偶交替,所以它们的特殊边在偶数行。如果网格的规模更大,我们可以用同样的方法找出所有的

特殊边。

网格的每个小方格刚好可以放入一个小方块,在游戏的一开始,有些小方格已经放上了小方块,另外的小方格没有放

。老 C 很讨厌下图所示的图形,如果他发现有一些小方块排列成了它讨厌的形状(特殊边的位置也要如图中所示),

就很容易弃疗,即使是经过任意次旋转、翻转后排列成讨厌的形状,老 C 也同样容易弃疗。

为了防止弃疗,老 C 决定趁自己还没有弃疗,赶紧移除一些格子里小方块,使得剩下的小方块不能构成它讨厌的形状

。但是游戏里每移除一个方块都是要花费一些金币的,每个方块需要花费的金币有多有少参差不齐。老 C 当然希望

尽可能少的使用游戏里的金币,但是最少要花费多少金币呢?老 C 懒得思考,就把这个问题交给你了

Input

第一行有3个正整数C, R, n,表示C列R行的网格中,有n个小方格放了小方块。

接下来n行,每行3个正整数x, y, w,表示在第x列第y行的小方格里放了小方块,移除它需要花费w个金币。保证不会

重复,且都在网格范围内。

1 ≤ C, R, n ≤ 10^5 , 1 ≤ w ≤ 10^4

Output

输出一行,包含一个整数,表示最少花费的金币数量。

Sample Input

2 2 4

1 1 5

1 2 6

2 1 7

2 2 8

Sample Output

5


简要题解

染色分层+最小割


想法

观察使老C弃疗的图形

发现它们都由特殊边两边的紫色格子,及一个蓝格子、一个绿格子组成。

由此我们可以给整张图染色

(为了方便我把两个紫格子分别染成紫与深蓝)

我们需要移除一些格子使图中不存在连续的 蓝-紫-深蓝-绿 或 绿-紫-深蓝-蓝

由此可以想到用最小割(有一句话说得好:灵感源于性质的相似性)

最小割即把对点的限制转换到对边的限制上。

开始建图。

S向每个绿格子连边,容量为绿格子的w

每个绿格子向相邻的紫格子与深蓝格子连边,容量为INF

紫格子与相邻深蓝格子互相连边,容量为两个格子w的min (其实这两个相邻的点是一体的,就相当于是一个大点。这两个点中间连边相当于拆大点。)

紫格子与深蓝格子向相邻的蓝格子连边,容量为INF

蓝格子向T连边,容量为蓝格子的w


代码

这道题A的真是不容易……

一开始懒得写hash表光写个hash,结果那么不幸就被卡上了……

(哎,这是第二次了……之前有一次cf没写hash表被hack了…)

调了好久好久,不开森。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>

#define INF 2000000007
#define P 100999

using namespace std;

typedef long long ll;
const int N = 100007;

struct node{
    int v,f;
    node *next,*rev;
}pool[N*10],*h[N];
int cnt;

void addedge(int u,int v,int f){
    node *p=&pool[++cnt],*q=&pool[++cnt];
    p->v=v;p->next=h[u];h[u]=p; p->f=f;p->rev=q;
    q->v=u;q->next=h[v];h[v]=q; q->f=0;q->rev=p;
}

int S,T;
int que[N],level[N];
bool bfs(){
    int head=0,tail=0,u,v;
    for(int i=S;i<=T;i++) level[i]=-1;
    level[S]=1; que[tail++]=S;
    while(head<tail){
        u=que[head++];
        for(node *p=h[u];p;p=p->next)
            if(p->f && level[v=p->v]==-1){
                level[v]=level[u]+1;
                que[tail++]=v;
            }
        if(level[T]!=-1) return true;
    }
    return false;
}
int find(int u,int f){
    int v,s=0,t;
    if(u==T) return f;
    for(node *p=h[u];p;p=p->next)
        if(p->f && s<f && level[v=p->v]==level[u]+1){
            t=find(v,min(p->f,f-s));
            if(t){
                s+=t;
                p->f-=t;
                p->rev->f+=t;
            }
        }
    if(!s) level[u]=-1;
    return s;
}
int dinic(){
    int flow=0;
    while(bfs()) flow+=find(S,INF);
    return flow;
}

int C,R,n;

struct data{
    int x,y,w,id;
}d[N];

int hash(int x,int y) {
    if(x<=0 || y<=0 || x>R || y>C) return P;
    return ((ll)x*N+y)%P;
}
vector<data> hh[P+1];

int check(int c,int x,int y){
    if(c==P) return 0;
    for(int i=0;i<hh[c].size();i++)
        if(hh[c][i].x==x && hh[c][i].y==y) return hh[c][i].id;
    return 0;
}

int main()
{
    scanf("%d%d%d",&C,&R,&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&d[i].y,&d[i].x,&d[i].w);
        d[i].id=i;
        hh[hash(d[i].x,d[i].y)].push_back(d[i]);
    }

    //addedge
    int t,xx,yy;
    S=0; T=n+1;
    for(int i=1;i<=n;i++){
        xx=d[i].x%2; yy=d[i].y%4;
        if((xx==1 && yy==1) || (xx==0 && yy==3)){ //purple
            t=check(hash(d[i].x,d[i].y+1),d[i].x,d[i].y+1);
            if(t) addedge(i,t,min(d[i].w,d[t].w));
        }
        else if((xx==1 && yy==2) || (xx==0 && yy==0)){ //dark blue
            t=check(hash(d[i].x,d[i].y-1),d[i].x,d[i].y-1);
            if(t) addedge(i,t,min(d[i].w,d[t].w));
        }
        else if((xx==1 && yy==3) || (xx==0 && yy==2)){ //green
            addedge(S,i,d[i].w);
            t=check(hash(d[i].x+1,d[i].y),d[i].x+1,d[i].y);
            if(t) addedge(i,t,INF);
            t=check(hash(d[i].x-1,d[i].y),d[i].x-1,d[i].y);
            if(t) addedge(i,t,INF);
            if(yy==3)
                t=check(hash(d[i].x,d[i].y-1),d[i].x,d[i].y-1);
            else t=check(hash(d[i].x,d[i].y+1),d[i].x,d[i].y+1);
            if(t) addedge(i,t,INF);
        }
        else{ //blue
            addedge(i,T,d[i].w);
            t=check(hash(d[i].x+1,d[i].y),d[i].x+1,d[i].y);
            if(t) addedge(t,i,INF);
            t=check(hash(d[i].x-1,d[i].y),d[i].x-1,d[i].y);
            if(t) addedge(t,i,INF);
            if(yy==1)
                t=check(hash(d[i].x,d[i].y-1),d[i].x,d[i].y-1);
            else t=check(hash(d[i].x,d[i].y+1),d[i].x,d[i].y+1);
            if(t) addedge(t,i,INF);
        }
    }

    printf("%d\n",dinic());

    return 0;
}

原文地址:https://www.cnblogs.com/lindalee/p/8447250.html

时间: 2024-11-08 19:54:17

[bzoj4823][洛谷P3756][Cqoi2017]老C的方块的相关文章

[bzoj4824][洛谷P3757][Cqoi2017]老C的键盘

Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也是一个程序员.有一天他悄悄潜入了老 C 的家中,想要看看这个 键盘究竟有何妙处.他发现,这个键盘共有n个按键,这n个按键虽然整齐的排成一列,但是每个键的高度却互不相同 .聪明的小 Q 马上将每个键的高度用 1 ~ n 的整数表示了出来,得到一个 1 ~ n 的排列 h1, h2,..., hn .为

bzoj4823: [Cqoi2017]老C的方块(最小割)

4823: [Cqoi2017]老C的方块 题目:传送门 题解: 毒瘤题ORZ.... 太菜了看出来是最小割啥边都不会建...狂%大佬强强强   黑白染色?不!是四个色一起染,四层图跑最小割... 很惊奇的发现染完色之后只要是不喜欢的图形都一定可以由黄-->黑-->红-->绿 组成 那就很nice啦...兴高采烈的去敲代码...结果10^5*10^5???搞毛线...太弱了ORZ,又看了一波大佬的操作,用map存! woc...不谈了不谈了...撸撸撸(分情况分到想屎...虽然不多) 注

[bzoj4815] [洛谷P3700] [Cqoi2017] 小Q的表格

Description 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理. 每当小Q不知道如何解决时,就只好向你求助.为了完成任务,小Q需要列一个表格,表格 有无穷多行,无穷多列,行和列都从1开始标号.为了完成任务,表格里面每个格子都填了 一个整数,为了方便描述,小Q把第a行第b列的整数记为f(a,b),为了完成任务,这个表格要 满足一些条件: (1)对任意的正整数a,b,都要满足f(a,b)=f(b,a): (2)对任意的正整数a,b,都要 满

Bzoj4823 [Cqoi2017]老C的方块

没有题面,懒得手打 网络流 最小割 码农题(误) 一开始是冲着n<=5000的部分分写了网络流,结果神奇地发现似乎就是正解. 说好的dinic时间复杂度上界$O(V^2 E)$呢……网络流不愧是玄学算法. 放一张题目里的图 四种图案: 观察这四种图案和它们旋转/翻转以后的样子,可以发现一个共同点:每种图案都是由“中心一条蓝色边和它相邻的两个方块”,以及另外两个邻接的方块组成的 范围画出来就是这个样子: 可以发现“另外两个邻接的方块”肯定一个在蓝线左边一个在蓝线右边. 先说一种错误的想法: 将每个

BZOJ 4823: [Cqoi2017]老C的方块

分析: 我觉得我的网络流白学了...QAQ... 其实数据范围本是无法用网络流跑过去的,然而出题者想让他跑过去,也就跑过去了... 看到题目其实感觉很麻烦,不知道从哪里入手,那么仔细观察所给出的有用信息... 我们考虑网格图是一个含有挡板的图,这个挡板的分布很有规律,大概是每一行的相邻两个挡板都隔了四个格子,并且奇数行的排列相同,偶数行的排列相同... 然后考虑不合法的方块形状有什么共同点:仔细观察就会发现,所有的不合法图形中,挡板的左边至少有一个格子,右边至少有一个格子,并且左边的格子连着一个

【题解】CQOI2017老C的方块

网络流真的是一种神奇的算法.在一张图上面求感觉高度自动化的方案一般而言好像都是网络流的主阵地.讲真一开始看到这道题也有点懵,题面很长,感觉很难的样子.不过,仔细阅读了题意之后明白了:我们所要做的就是要用最小的代价,使得最后的图中不能出现给定的四种图案. 实际上之前做过一道非常毒瘤的网络流题目[无限之环].当时就思考了一下:为什么出题人规定不能旋转直线管子?原因就是因为这样的图建不出来,它与不具有其他的管子的特点.那么可以断定:给出的这四个图案必然也是非常特殊的图形,否则不会只有这四个/不会是这四

约数和问题(codevs2606&amp;amp;&amp;amp;洛谷2424)

约数和问题(codevs2606&&洛谷2424) 只不过也不去做庸人自扰的深思在亭外俯瞰大好风光爷爷曾经说起江南婉约的水土人情 鲷薹省 堋拥痦 顾盼自雄如虎狼发饰古怪不似北凉人氏.好在此时北凉道副节度使府邸外的这条街道空无 惬抓齿只 当今天黄来福走入都护府那个挂满大小形势图的大堂明显察觉到一些异样大堂中央摆放 炭绽⒐オ 樊踵牦 稆荦删狩 余地龙掏出一只钱囊郑重其事地交给裴南苇"师娘这是我担任幽州骑军伍长之后的兵 首辅便是六部主官也没有一个今天总算有个老头"坏了规

洛谷P1220 关路灯

洛谷1220 关路灯 题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯.    为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电.他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯.开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大

洛谷P1337 【[JSOI2004]平衡点 / 吊打XXX】(模拟退火)

洛谷题目传送门 很可惜,充满Mo力的Mo拟退火并不是正解.不过这是一道最适合开始入手Mo拟退火的好题. 对模拟退火还不是很清楚的可以看一下 这道题还真和能量有点关系.达到平衡稳态的时候,物体的总能量应该是最小的.而总的能量来源于每个物体的重力势能之和.要想让某个物体势能减小,那就让拉着它的绳子在桌面下方的长度尽可能的长,也就是桌面上的要尽可能短.由此看来,某个物体的势能与桌面上的绳子的长度.物体重量都成正比. 于是,为了找到平衡点,我们要找一个点使得\(\sum_{i=1}^n d_i*w_i\