[CSP-S模拟测试]:marshland(最大费用可行流)
题目描述
前方有一片沼泽地。
方便地,我们用一个$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(最大费用可行流)的更多相关文章
- 【CF708D】Incorrect Flow 最小费用可行流
[CF708D]Incorrect Flow 题意:给你一个点数为n,边数为m的流网络,每条边有一个容量c和流量f,这个网络可能是不合法的.你可以花费1的代价使c或f减少或增加1,可以修改无限次.你不 ...
- [Ahoi2014]支线剧情[无源汇有下界最小费用可行流]
3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1538 Solved: 940[Submit][Statu ...
- BZOJ 3876 支线剧情 有源汇有上下界最小费用可行流
题意: 给定一张拓扑图,每条边有边权,每次只能从第一个点出发沿着拓扑图走一条路径,求遍历所有边所需要的最小边权和 分析: 这道题乍一看,可能会想到什么最小链覆盖之类的,但是仔细一想,会发现不行,一是因 ...
- BZOJ 2055 80人环游世界 有上下界最小费用可行流
题意: 现在有这么一个m人的团伙,也想来一次环游世界. 他们打算兵分多路,游遍每一个国家. 因为他们主要分布在东方,所以他们只朝西方进军.设从东方到西方的每一个国家的编号依次为1...N.假若第 ...
- BZOJ 3876 [AHOI/JSOI2014]支线剧情 (最小费用可行流)
题面:洛谷传送门 BZOJ传送门 题目大意:给你一张有向无环图,边有边权,让我们用任意条从1号点开始的路径覆盖这张图,需要保证覆盖完成后图内所有边都被覆盖至少一次,求覆盖路径总长度的最小值 最小费用可 ...
- HDU 6118 度度熊的交易计划 最大费用可行流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6118 题意:中文题 分析: 最小费用最大流,首先建立源点 s ,与超级汇点 t .因为生产一个商品需要 ...
- BZOJ 3876 支线剧情(有上下界的无源汇最小费用可行流)
3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 1783 Solved: 1079 [Submit][St ...
- BZOJ-2324 营救皮卡丘 最小费用可行流+拆下界+Floyd预处理
准备一周多的期末,各种爆炸,回来后状态下滑巨快...调了一晚上+80%下午 2324: [ZJOI2011]营救皮卡丘 Time Limit: 10 Sec Memory Limit: 256 MB ...
- HDU6118:度度熊的交易计划(入门级最小费用可行流)
度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题: 喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区. 由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但 ...
随机推荐
- 20190820 On Java8 第十章 接口
第十章 接口 接口和抽象类提供了一种将接口与实现分离的更加结构化的方法. 抽象类和方法 包含抽象方法的类叫做抽象类.如果一个类包含一个或多个抽象方法,那么类本身也必须限定为抽象的,否则,编译器会报错. ...
- c语言1博客作业12-学期总结
一.我学到的内容 二.收获总结 2.1我的收获 链接: c语言1博客作业01:https://www.cnblogs.com/dy-985211/p/11578914.html c语言1博客作业02: ...
- 无法启动Sql Server服务
本文首发地址为hilsion的博客 今天遇到一个无法启动SQL Server服务的问题,具体报错如下: 根据错误提示,去到WINDOWS的事件查看器.在WIN10上,右击右下角的菜单图标: 然后依次点 ...
- Jmeter中Bean shell脚本格式修改为utf-8
遇到的问题: 在做 一个发贴的接口测试时发现,发送数字+纯字母贴子时,可以正常请求成功.但当贴内容为中文时,服务端编码为乱码??. 原因: jmeter中,shell脚本的默认的格式为GBK,所以我在 ...
- 《JAVA设计模式》之命令模式(Command)
在阎宏博士的<JAVA与模式>一书中开头是这样描述命令(Command)模式的: 命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. ...
- shell 删除项目日志
删除半年之前的日志 find 后面紧跟目录 .为当前目录 -type f 指定查找的是文件 -mtime +180 查找180天之前的 -name 文件名筛选 -exec -rm -rf 执行的 ...
- Python入门习题2.蟒蛇绘制(turtle库)
例2.调用turtle库中的若干函数来绘制蟒蛇,要求:(1)主体窗口宽650像素,高度350像素,窗口左侧与屏幕左侧像素距离200,窗口顶部与屏幕顶部像素距离200:(2)画笔落点在原点反向前进250 ...
- [POJ3612] Telephone Wire(暴力dp+剪枝)
[POJ3612] Telephone Wire(暴力dp+剪枝) 题面 有N根电线杆,初始高度为h[i],要给相邻的两根连线.可以选择拔高其中一部分电线杆,把一根电线杆拔高\(\Delta H\)的 ...
- TiKV集群配置记录
环境:两台ubuntu 18.04 pc tidb / pd: 192.168.1.150 tikv: 192.1681.1.151 主要参考https://pingcap.com/docs-cn/d ...
- redis命令行命令
配置文件设置密码认证 修改redis.conf去掉#requirepass foobared前面的#,foobared就是密码,可以进行修改 redis命令设置密码认证config set requi ...