列表

详情


NC19949. [CQOI2017]老C的方块

描述

老 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 懒得思考,就把这个问题交给你了

输入描述

第一行有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

输出描述

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

示例1

输入:

2 2 4
1 1 5
1 2 6
2 1 7
2 2 8

输出:

5

说明:

如图所示,2×2的网格里,每个小方格都放了小方块,移除需要花费的金币数量如图中标注所示。这4个小方块恰好构成了一个老 C 讨厌的图形,将第1列第1行的小方块移除,花费5个金币,剩下的方块不能形成老 C 讨厌的图形,显然这种移除方案花费的金币最少。

示例2

输入:

3 3 7 
1 1 10 
1 2 15 
1 3 10 
2 1 10 
2 2 10 
2 3 10 
3 1 10

输出:

15

说明:

如图所示。容易发现,如果不移除第 1 列第 2 行的小方块,则至少要移除两个小方块,才能不包含老 C 讨厌的图形,花费至少 20 个金币;而删除第 1 列第 2 行的小方块后,原有的讨厌图形全都不存在了,只需要花费 15 个金币。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 309ms, 内存消耗: 17752K, 提交时间: 2022-12-30 11:24:51

#include<bits/stdc++.h>
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
const int N = 5e5 + 10, M = 5e5 + 10, INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int>PII;
int h[N], e[M], ne[M], f[M], idx, d[N], n, m, S, T, cur[M], t, x[N], y[N];

void add(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], f[idx] = c, h[a] = idx ++;
    e[idx] = a, ne[idx] = h[b], f[idx] = 0, h[b] = idx ++; 
}

bool bfs()
{
    queue<int>q;
    memset(d, -1, sizeof d);
    q.push(S);
    d[S] = 0;
    cur[S] = h[S];
    while(!q.empty())
    {
        auto t = q.front();
        q.pop();
        
        for(int i = h[t]; ~i; i = ne[i])
        {
            int j = e[i];
            if((d[j] == -1) && f[i])
            {
                d[j] = d[t] + 1;
                cur[j] = h[j];
                if(j == T) return true;
                q.push(j);
            }
        }
    }
    return false;
}

int find(int u, int limit)
{
    if(u == T) return limit;
    int flow = 0;
    for(int i = cur[u]; ~i && flow < limit; i = ne[i])
    {
        int j = e[i];
        cur[u] = i;
        if((d[j] == d[u] + 1) && f[i])
        {
            int t = find(j, min(f[i], limit - flow));
            if(!t) d[j] = -1;
            f[i] -= t, f[i ^ 1] += t, flow += t;
        }
    }
    return flow;
}

int dinic()
{
    int r = 0, flow;
    while(bfs()) while(flow = find(S, 0x3f3f3f3f)) r += flow;
	return r;    
}
map<PII, int>mp;
// int get(int x, int y)
// {
// 	if(x % 4 == 1) return ((y & 1) ? 2 : 1);
// 	if(x % 4 == 2) return ((y & 1) ? 3 : 4);
// 	if(x % 4 == 3) return ((y & 1) ? 1 : 2);
// 	return ((y & 1) ? 4 : 3);
// }
int get(int x, int y) {
if (x % 4 == 1) return (y & 1) ? 2 : 1;
if (x % 4 == 2) return (y & 1) ? 3 : 4;
if (x % 4 == 3) return (y & 1) ? 4 : 3;
if (x % 4 == 0) return (y & 1) ? 1 : 2;
return 0;
}

int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};


void solve()
{
	cin >> n >> m >> t;
	memset(h, -1, sizeof h);
	S = N - 1, T = S - 1;
	for(int i = 1; i <= t; i ++ )
	{
		int w;
		cin >> x[i] >> y[i] >> w;
		mp[{x[i], y[i]}] = i;
		add(i, i + t, w); // 拆点
	}

	for(int i = 1; i <= t; i ++ )
	{
		int t1 = get(x[i], y[i]);
		if(t1 == 1) add(S, i, INF);
		if(t1 == 4) add(i + t, T, INF);
		for(int d = 0; d < 4; d ++ )
		{
			int a = x[i] + dx[d], b = y[i] + dy[d];
			if(!mp.count({a, b})) continue;
			int j = mp[{a, b}], t2 = get(a, b);
			if(t1 == 1 && t2 == 2) add(i + t, j, INF);
			if(t1 == 2 && t2 == 3) add(i + t, j, INF);
			if(t1 == 3 && t2 == 4) add(i + t, j, INF);
		}
	}

	cout << dinic() << '\n';
}
signed main()
{
	io;
	int T = 1;
	//cin >> T;
	while(T -- )
	solve();
}

C++(clang++11) 解法, 执行用时: 148ms, 内存消耗: 20984K, 提交时间: 2021-02-14 12:59:36

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int N = 1e5+5;
const int inf = 2e9;
struct edge{int to,nxt,w;}a[N<<4];
int n,x[N],y[N],val[N],col[N],S,T,head[N],cnt=1,dep[N],cur[N];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
map<int,int>M[N];queue<int>Q;
void link(int u,int v,int w){
    a[++cnt]=(edge){v,head[u],w};head[u]=cnt;
    a[++cnt]=(edge){u,head[v],0};head[v]=cnt;
}
bool bfs(){
    memset(dep,0,sizeof(dep));
    dep[S]=1;Q.push(S);
    while (!Q.empty()){
        int u=Q.front();Q.pop();
        for (int e=head[u];e;e=a[e].nxt)
            if (a[e].w&&!dep[a[e].to])
                dep[a[e].to]=dep[u]+1,Q.push(a[e].to);
    }
    return dep[T];
}
int dfs(int u,int f){
    if (u==T) return f;
    for (int &e=cur[u];e;e=a[e].nxt)
        if (a[e].w&&dep[a[e].to]==dep[u]+1){
            int tmp=dfs(a[e].to,min(a[e].w,f));
            if (tmp) {a[e].w-=tmp;a[e^1].w+=tmp;return tmp;}
        }
    return 0;
}
int dinic(){
    int res=0;
    while (bfs()){
        for (int i=1;i<=T;++i) cur[i]=head[i];
        while (int tmp=dfs(S,inf)) res+=tmp;
    }
    return res;
}
void build1(int v){
    for (int d=0;d<4;++d){
        int i=x[v]+dx[d],j=y[v]+dy[d],u=M[i][j];
        if (u)
            if (col[u]==2) link(v,u,min(val[u],val[v]));
            else link(u,v,inf);
    }
}
void build2(int u){
    for (int d=0;d<4;++d){
        int i=x[u]+dx[d],j=y[u]+dy[d],v=M[i][j];
        if (v)
            if (col[v]==1) link(u,v,min(val[u],val[v]));
            else link(u,v,inf);
    }
}
int main(){
    gi();gi();n=gi();S=n+1;T=S+1;
    for (int i=1;i<=n;++i){
        x[i]=gi(),y[i]=gi(),val[i]=gi();
        M[x[i]][y[i]]=i;
        col[i]=(x[i]%4>=2)*2+(((x[i]+y[i])&1)^1);
    }
    for (int i=1,j;i<=n;++i)
        if (col[i]==0) link(S,i,val[i]);
        else if (col[i]==1) build1(i);
        else if (col[i]==2) build2(i);
        else link(i,T,val[i]);
    printf("%d\n",dinic());return 0;
}

上一题