[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个商品,但 ...
随机推荐
- WCF权限认证多种方式
WCF身份验证一般常见的方式有:自定义用户名及密码验证.X509证书验证.ASP.NET成员资格(membership)验证.SOAP Header验证.Windows集成验证.WCF身份验证服务(A ...
- L2 Regularization for Neural Nerworks
L2 Regularization是解决Variance(Overfitting)问题的方案之一,在Neural Network领域里通常还有Drop Out, L1 Regularization等. ...
- python 按二维数组的某行或列排序 (numpy lexsort)
lexsort支持对数组按指定行或列的顺序排序:是间接排序,lexsort不修改原数组,返回索引. (对应lexsort 一维数组的是argsort a.argsort()这么使用就可以:argsor ...
- [LeetCode] 137. Single Number II (位操作)
传送门 Description Given an array of integers, every element appears three times except for one, which ...
- EasyUI的datagrid列属性添加超链接
$("#dg").datagrid({ url: "../Ajax/PurchaseAjax.ashx", queryParams: ...
- Django csrf,xss,sql注入
一.csrf跨站请求伪造(Cross-site request forgery) CSRF的攻击原理:简单说就是利用了高权限帐号(如管理员)的登录状态或者授权状态去做一些后台操作,但实际这些状态并没有 ...
- mysql: "Warning: Using a password on the command line interface can be insecure." 解决方法
错误重现: 命令行或者shell脚本中执行以下命令,如果您当前服务器mysql版本是大于5.6的,则会出现警告:Warning: Using a password on the command lin ...
- <搬运> SQL语句百万数据量优化方案
一:理解sql执行顺序 在sql中,第一个被执行的是from语句,每一个步骤都会产生一个虚拟表,该表供下一个步骤查询时调用,比如语句:select top 10 column1,colum2,max( ...
- [洛谷P3261] [JLOI2015]城池攻占(左偏树)
不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!! 花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸.基本上改得和题解完全一样了我才过了这道题!真的烦 ...
- 三种分布式锁 简易说说(包含前一篇提到的redis分布式锁)
大多数互联网系统都是分布式部署的,分布式部署确实能带来性能和效率上的提升,但为此,我们就需要多解决一个分布式环境下,数据一致性的问题. 当某个资源在多系统之间,具有共享性的时候,为了保证大家访问这个资 ...