题目描述

前方有一片沼泽地。
方便地,我们用一个$n\times n$的网格图来描述它,每一个格子代表着沼泽地的一小片区域。其中$(1,1)$代表网格图的左上角,$(n,n)$代表网格图的右下角。若用$X$表示行数,$Y$表示列数,那么$X+Y$为奇数的格子有一个危险度为$0$。
为了保障人们的安全,你有$m$个长相怪异的大石头,你可以选一些石头放在网格图上的某些格子,石头可以看成一个$'L'$形的块,并且占三个格子,它通过旋转有四种方式供放置,仅会使得在拐角处的那个格子危险度减为$0$。
网格图中还有$k$个位置是“禁止位置”,石头的任何部位都不能位于这些格子上,且这些位置的危险度一定为$0$。
现在你需要知道放置一些石头之后最小危险度之和是多少。(石头可以不放完)


输入格式

第一行三个整数$n,m,k$。
接下来$n$行每行$n$个整数,表示每个格子的危险读,保证$X+Y$为偶数的格子和禁止位置的格子的危险度为$0$。
接下来$k$行每行$2$个整数$X,Y$,表示禁止位置的坐标,注意可能会出现重复的禁止位置。


输出格式

输出一行一个整数代表最小的危险度之和。


样例

样例输入1:

3 3 1
0 1 0
2 0 1
0 1 0
1 3

样例输出1:

3

样例输入2:

3 3 4
0 2 0
0 0 4
0 3 0
1 3
2 1
2 2
3 1

样例输出2:

9


数据范围与提示

对于$10\%$的数据,满足$n\leqslant 4$。
对于$30\%$的数据,满足$n\leqslant 10$。
对于$100\%$的数据,满足$n\leqslant 50$。
对于所有数据,满足$0\leqslant m\leqslant \frac{n^2}{3},0\leqslant k\leqslant n^2,0\leqslant V_{x,y}\leqslant {10}^6$。


题解

在坐的各位应该都能看出来大石头的拐角一定压住有危险度的点了叭?为什么我也不赘述了,这要是都想不出来尽早退役。

$0\%$算法:

乍一看你可能会觉得是道$DP$,设$dp[i][j][0/1][0/1/2/3]$表示在$(i,j)$有没有放石头,放了的话朝向是哪儿的最小危险度,看似简单,打起来瞬间见祖宗。

于是弃掉这种做法,事实证明我打了$150+$行的状态转移一分没拿。

有的时候假的贪心是能在关键时刻出奇迹的,比方说着道题。

我们先把所有格子的危险度从小到大排名,然后依次覆盖,可以覆盖就覆盖,不可以就跳过。

为了提高正确率,我们在覆盖当前格子的同时也要考虑一下其它的格子,比方说下面这张图,我们在覆盖红色格子的同时可能会影响到蓝色格子:

那么我们可以考虑将蓝色格子再比较大小,然后朝危险度最小的那个格子的方向放置:

这种贪心思想大大提高了正确率,但是它依然是不正确的,比方说你可能放置了一块石头压住了一个危险度较大的格子,但是却使好多危险度较小的格子被阻碍放置。

时间复杂度:$\Theta(n^2)$。

期望得分:$0$分。

实际得分:$40$分。

$100\%$算法:

对于卓越的我们,当然不能只是止步于上面那个假的贪心啦(虽说考场上我也就是交了上面那个假的贪心……)

那么考虑正解,偷偷看一眼数据范围,$n$好小,所以我们可以考虑网络流(我也不知道为什么就一定要考虑网络流),在筛选一番之后发现这是一个最大费用可行流,那么怎么连边呢?

认真观察之后发现,一个$L$是由一个$X+Y$为奇数和两个$X+Y$为偶数的点组成,那也不够哇?在认真观察,发现$X+Y$为偶数的那两个点一定是由一个为奇$+$奇,一个为偶$+$偶组成的,所以将有危险度的点连边,并将$L$的剩下两个点连边向源点和汇点即可,对于这道题建议使用$EK$,下面的标程使用的也是$EK$。

我的做法是每次只流一个,代码复杂度比较低,但是速度并没有优势。

在注意一下流量是$m$即可。

时间复杂度:$\Theta(n^4)$(也许是吧,我也不太会算……)

期望得分:$100$分。

实际得分:$100$分。


代码时刻

$40$分假贪心:

#include<bits/stdc++.h>
using namespace std;
struct rec
{
int x,y,w;
}e[50000];
int n,m,k;
int cnt;
int Map[100][2500];
bool vis[100][2500];
long long ans,sum;
bool cmp(rec a,rec b){return a.w>b.w;}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&Map[i][j]);
if(Map[i][j])
{
e[++cnt].x=i;
e[cnt].y=j;
e[cnt].w=Map[i][j];
ans+=Map[i][j];
}
}
sort(e+1,e+cnt+1,cmp);
while(k--)
{
int x,y;
scanf("%d%d",&x,&y);
vis[x][y]=1;
}
for(int i=0;i<=n+1;i++)vis[i][0]=vis[i][n+1]=1;
for(int i=0;i<=n+1;i++)vis[0][i]=vis[n+1][i]=1;
for(int i=1;i<=cnt&&m;i++)
{
int x=e[i].x;
int y=e[i].y;
int w=e[i].w;
int m1=Map[x-1][y-1];
int m2=Map[x-1][y+1];
int m3=Map[x+1][y-1];
int m4=Map[x+1][y+1];
if(!vis[x-1][y]&&!vis[x][y-1]&&!vis[x+1][y]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=1;
if(m1<=m2&&m1<=m3&&m1<=m4){vis[x-1][y]=vis[x][y-1]=1;continue;}
if(m2<=m1&&m2<=m3&&m2<=m4){vis[x-1][y]=vis[x][y+1]=1;continue;}
if(m3<=m1&&m3<=m2&&m3<=m4){vis[x+1][y]=vis[x][y-1]=1;continue;}
if(m4<=m1&&m4<=m2&&m4<=m3){vis[x+1][y]=vis[x][y+1]=1;continue;}
}
if(!vis[x][y-1]&&!vis[x+1][y]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=vis[x+1][y]=1;
if(m3<=m4){vis[x][y-1]=1;continue;}
else {vis[x][y+1]=1;continue;}
}
if(!vis[x-1][y]&&!vis[x+1][y]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=vis[x][y+1]=1;
if(m2<=m4){vis[x-1][y]=1;continue;}
else {vis[x+1][y]=1;continue;}
}
if(!vis[x-1][y]&&!vis[x][y-1]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=vis[x-1][y]=1;
if(m1<=m2){vis[x][y-1]=1;continue;}
else {vis[x][y+1]=1;continue;}
}
if(!vis[x-1][y]&&!vis[x][y-1]&&!vis[x+1][y])
{
sum+=w;
m--;
vis[x][y]=vis[x][y-1]=1;
if(m1<=m3){vis[x-1][y]=1;continue;}
else {vis[x+1][y]=1;continue;}
}
if(!vis[x-1][y]&&!vis[x][y-1])
{
sum+=w;
m--;
vis[x][y]=vis[x-1][y]=vis[x][y-1]=1;
continue;
}
if(!vis[x-1][y]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=vis[x-1][y]=vis[x][y+1]=1;
continue;
}
if(!vis[x+1][y]&&!vis[x][y-1])
{
sum+=w;
m--;
vis[x][y]=vis[x+1][y]=vis[x][y-1]=1;
continue;
}
if(!vis[x+1][y]&&!vis[x][y+1])
{
sum+=w;
m--;
vis[x][y]=vis[x+1][y]=vis[x][y+1]=1;
continue;
}
}
cout<<ans-sum<<endl;
return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
int w;
}e[1000000];
int head[5000],cnt;
int n,m,k;
int tot=2;
int Map[51][51];
bool vis[51][51];
int S[51][51],T[51][51];
int que[1000000],dis[1000000],g[1000000];
int dp[5000][5000],wzc[51][51],c[5000][5000];
bool v[1000000];
int ans;
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
bool bfs()
{
for(int i=1;i<=tot;i++)
{
dis[i]=-20020923;
g[i]=v[i]=0;
}
dis[1]=0;
v[1]=1;
int he=1,ta=1;
que[ta]=1;
while(he<=ta)
{
for(int i=head[que[he]];i;i=e[i].nxt)
if(dp[que[he]][e[i].to]&&dis[que[he]]+c[que[he]][e[i].to]>dis[e[i].to])
{
dis[e[i].to]=dis[que[he]]+c[que[he]][e[i].to];
g[e[i].to]=que[he];
if(!v[e[i].to])
{
v[e[i].to]=1;
que[++ta]=e[i].to;
}
}
v[que[he]]=0;
he++;
}
return dis[2]>0;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&Map[i][j]);
ans+=Map[i][j];
}
while(k--)
{
int x,y;
scanf("%d%d",&x,&y);
vis[x][y]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j])
{
S[i][j]=++tot;
T[i][j]=++tot;
add(tot-1,tot,Map[i][j]);
add(tot,tot-1,Map[i][j]);
c[tot-1][tot]=Map[i][j];
c[tot][tot-1]=-Map[i][j];
dp[tot-1][tot]++;
}
else if(!vis[i][j]&&!((i+j)&1))
{
wzc[i][j]=++tot;
if(i&1)
{
add(1,tot,0);
add(tot,1,0);
dp[1][tot]++;
}
else
{
add(tot,2,0);
add(2,tot,0);
dp[tot][2]++;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j])
{
if(i-1>0&&!vis[i-1][j])
{
if((i-1)&1)
{
add(wzc[i-1][j],S[i][j],0);
add(S[i][j],wzc[i-1][j],0);
dp[wzc[i-1][j]][S[i][j]]++;
}
else
{
add(T[i][j],wzc[i-1][j],0);
add(wzc[i-1][j],T[i][j],0);
dp[T[i][j]][wzc[i-1][j]]++;
}
}
if(j-1>0&&!vis[i][j-1])
{
if(i&1)
{
add(wzc[i][j-1],S[i][j],0);
add(S[i][j],wzc[i][j-1],0);
dp[wzc[i][j-1]][S[i][j]]++;
}
else
{
add(T[i][j],wzc[i][j-1],0);
add(wzc[i][j-1],T[i][j],0);
dp[T[i][j]][wzc[i][j-1]]++;
}
}
if(i+1<=n&&!vis[i+1][j])
{
if((i+1)&1)
{
add(wzc[i+1][j],S[i][j],0);
add(S[i][j],wzc[i+1][j],0);
dp[wzc[i+1][j]][S[i][j]]++;
}
else
{
add(T[i][j],wzc[i+1][j],0);
add(wzc[i+1][j],T[i][j],0);
dp[T[i][j]][wzc[i+1][j]]++;
}
}
if(j+1<=n&&!vis[i][j+1])
{
if(i&1)
{
add(wzc[i][j+1],S[i][j],0);
add(S[i][j],wzc[i][j+1],0);
dp[wzc[i][j+1]][S[i][j]]++;
}
else
{
add(T[i][j],wzc[i][j+1],0);
add(wzc[i][j+1],T[i][j],0);
dp[T[i][j]][wzc[i][j+1]]++;
}
}
}
k=0;
while(k<m&&bfs())
{
int flag=2;
while(g[flag])
{
ans-=c[g[flag]][flag];
dp[g[flag]][flag]--;
dp[flag][g[flag]]++;
flag=g[flag];
}
k++;
}
cout<<ans<<endl;
return 0;
}

rp++

[CSP-S模拟测试]:marshland(最大费用可行流)的更多相关文章

  1. 【CF708D】Incorrect Flow 最小费用可行流

    [CF708D]Incorrect Flow 题意:给你一个点数为n,边数为m的流网络,每条边有一个容量c和流量f,这个网络可能是不合法的.你可以花费1的代价使c或f减少或增加1,可以修改无限次.你不 ...

  2. [Ahoi2014]支线剧情[无源汇有下界最小费用可行流]

    3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1538  Solved: 940[Submit][Statu ...

  3. BZOJ 3876 支线剧情 有源汇有上下界最小费用可行流

    题意: 给定一张拓扑图,每条边有边权,每次只能从第一个点出发沿着拓扑图走一条路径,求遍历所有边所需要的最小边权和 分析: 这道题乍一看,可能会想到什么最小链覆盖之类的,但是仔细一想,会发现不行,一是因 ...

  4. BZOJ 2055 80人环游世界 有上下界最小费用可行流

    题意: 现在有这么一个m人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家.    因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第 ...

  5. BZOJ 3876 [AHOI/JSOI2014]支线剧情 (最小费用可行流)

    题面:洛谷传送门 BZOJ传送门 题目大意:给你一张有向无环图,边有边权,让我们用任意条从1号点开始的路径覆盖这张图,需要保证覆盖完成后图内所有边都被覆盖至少一次,求覆盖路径总长度的最小值 最小费用可 ...

  6. HDU 6118 度度熊的交易计划 最大费用可行流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6118 题意:中文题 分析: 最小费用最大流,首先建立源点 s ,与超级汇点 t .因为生产一个商品需要 ...

  7. BZOJ 3876 支线剧情(有上下界的无源汇最小费用可行流)

    3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 1783  Solved: 1079 [Submit][St ...

  8. BZOJ-2324 营救皮卡丘 最小费用可行流+拆下界+Floyd预处理

    准备一周多的期末,各种爆炸,回来后状态下滑巨快...调了一晚上+80%下午 2324: [ZJOI2011]营救皮卡丘 Time Limit: 10 Sec Memory Limit: 256 MB ...

  9. HDU6118:度度熊的交易计划(入门级最小费用可行流)

    度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但 ...

随机推荐

  1. Golang通过反射获取结构体的标签

    Golang通过反射获取结构体的标签 例子: package main import ( "fmt" "reflect" ) type resume struc ...

  2. Cookie 记录最后访问时间

    package cn.gs.ly.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.D ...

  3. upc组队赛17 Stone Game【极小值】

    Stone Game 题目链接 题目描述 Alice and Bob are always playing game! The game today is about taking out stone ...

  4. Vulhub搭建

    Vulhub是一个比较全面的漏洞集合,收集了近年来许多的重要漏洞,以开源的形式呈现,以docker的形式进行环境配置,提供了更简单的漏洞复现,只需要简单的命令即可实现漏洞复现. 官网  https:/ ...

  5. #C语言l作业04

    这个作业属于哪个课程** C语言程序设计ll 这个作业的要求 (https://edu.cnblogs.com/campus/zswxy/SE2019-4/homework/9776) 我在这个课程的 ...

  6. 《JAVA设计模式》之代理模式(Proxy)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述代理(Proxy)模式的: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式的结 ...

  7. java_第一年_JavaWeb(8)

    前面说到,JSP在运行时会被编译成Servlet源代码,通过_jspServlet方法处理请求,此时该方法会传递和提供9个与web开发相关的对象进行使用,开发人员在JSP页面通过对这些变量即可引用这9 ...

  8. C#.NET动态页面静态化生成

    一,动态页面生成静态也的思路是怎样呢? 1>首先我们都是需要有一个静态模板,这模板的作用就是静态页的最基本模板,如下代码: <!DOCTYPE HTML PUBLIC "-//W ...

  9. CSS3中的弹性盒子模型

    介绍 在css2当中,存在标准模式下的盒子模型和IE下的怪异盒子模型.这两种方案表示的是一种盒子模型的渲染模式.而在css3当中,新增加了弹性盒子模型,弹性盒子模型是一种新增加的强大的.灵活的布局方案 ...

  10. Java实现二分法(折半)查找数组中的元素

    二分查找 算法思想:又叫折半查找,要求待查找的序列有序.每次取中间位置的值与待查关键字比较,如果中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小,则在后半部分 ...