表示“必须选”的模型

题目大意


题目分析

一个格子有四种方式看上去很难处理。将横竖两个方向分开考虑,会发现:因为收益只与相邻格子是否连通有关,所以可以将一个格子拆成表示横竖两个方向的,互相独立的点。

上图的格子里四个方向红边表示的就是一个格子的可能方向;拆点后所连蓝边的容量为1,费用即为连通两个格子的收益。

但是这样建图不能够表示某些格子必须要选。

考虑一个格子如果被选择了会发生什么:因为每个格子都处在环上,那么被选择的网格一定可以通过其他节点走到汇点。这意味着一个格子拆成的两个节点之间的边就可以先不建,而若最大流不等于网格总数,即有节点不可能被合法选中。

建图的时候一定要先理解清楚,因为有很多种错误方式,下图就是其中一个。

 #include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
const int maxn = ;
const int maxm = ;
const int INF = 2e9; struct Edge
{
int u,v,f,c,cst;
Edge(int a=, int b=, int c=, int d=, int e=):u(a),v(b),f(c),c(d),cst(e) {}
}edges[maxm];
int sne,n,m,S,T;
bool ess[][],inq[maxn];
int tagl[][],tagr[][],valc[][],valr[][];  //tagl为入点,tagr为出点
int edgeTot,head[maxn],nxt[maxm],flw[maxn],cst[maxn],bck[maxn]; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void addedge(int u, int v, int c, int cst)
{
edges[edgeTot] = Edge(u, v, , c, cst), nxt[edgeTot] = head[u], head[u] = edgeTot++;
edges[edgeTot] = Edge(v, u, , , -cst), nxt[edgeTot] = head[v], head[v] = edgeTot++;
}
void maxFlow()
{
int mxFlw = , cost = ;
for (;;)
{
std::queue<int> q;
memset(flw, , sizeof flw);
memset(bck, , sizeof bck);
memset(cst, 0x3f3f3f3f, sizeof cst);
q.push(S), flw[S] = INF, cst[S] = ;
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop(), inq[tmp] = ;
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (cst[tmp]+edges[i].cst < cst[v]&&edges[i].f < edges[i].c){
bck[v] = i, cst[v] = cst[tmp]+edges[i].cst;
flw[v] = std::min(flw[tmp], edges[i].c-edges[i].f);
if (!inq[v]) inq[v] = , q.push(v);
}
}
}
if (!flw[T]) break;
for (int i=T; i!=S; i=edges[bck[i]].u)
edges[bck[i]].f += flw[T], edges[bck[i]^].f -= flw[T];
mxFlw += flw[T], cost += cst[T]*flw[T];
}
if (mxFlw!=n*m) puts("Impossible");
else printf("%d\n",-cost);
}
int main()
{
sne = read();
for (int cse=; cse<=sne; cse++)
{
printf("Case #%d: ",cse);
memset(ess, , sizeof ess);
memset(head, -, sizeof head);
edgeTot = , n = read(), m = read();
for (int i=; i<=n; i++)
for (int j=; j<m; j++)
valc[i][j] = read();
for (int i=; i<n; i++)
for (int j=; j<=m; j++)
valr[i][j] = read();
for (int i=, cnt=; i<=n; i++)
for (int j=; j<=m; j++)
tagl[i][j] = ++cnt, tagr[i][j] = ++cnt;
S = , T = tagr[n][m]+;
for (int i=; i<=n; i++)
for (int j=; j<=m; j++)
if ((i+j)&){    //为避免重复建边的处理技巧
if (j+ <= m) addedge(tagl[i][j], tagr[i][j+], , -valc[i][j]);
if (j- >= ) addedge(tagl[i][j], tagr[i][j-], , -valc[i][j-]);
}else{
if (i+ <= n) addedge(tagl[i][j], tagr[i+][j], , -valr[i][j]);
if (i+ >= ) addedge(tagl[i][j], tagr[i-][j], , -valr[i-][j]);
}
for (int i=read(); i; i--) ess[read()][read()] = ;
for (int i=; i<=n; i++)
for (int j=; j<=m; j++)
{
addedge(S, tagl[i][j], , );
addedge(tagr[i][j], T, , );
if (!ess[i][j]) addedge(tagl[i][j], tagr[i][j], , );
}
maxFlow();
}
return ;
}

END

【费用流】 ICPC 2016 China Final J. Mr.Panda and TubeMaster的更多相关文章

  1. ICPC 2016 China Final J. Mr.Panda and TubeMaster【最大费用最大流】

    有一种限制下界强制选的,但是也可以不用 把每个格点拆成两个,一个连s一个连t,对于不是必选的连中间连流量1费用0边表示不选,然后黑白染色,黑点连横着白点连竖着,边权就是这条水管的权值,然后跑最大费用最 ...

  2. China Final J - Mr.Panda and TubeMaster

    和一般的管道不同 不能类似“无限之环”或者“弯弯国”的建图,因为这两个题都是某些位置必须有,或者必须没有 但是本题可以有的位置随意,不能限制某个位置要么流2,要么流0,(实际上可能流了1过去) 所以建 ...

  3. J - Mr.Panda and TubeMaster

    题解 我们可以把每个格子拆成两个点,一个表示横向的,一个表示纵向的,相邻的格子横向和纵向连边. 如果直接按照题意做的话,我们应当在横向和纵向的点之间连边,有限制的边设下界为1,然后跑可行流. 或者考虑 ...

  4. Gym101194J Mr.Panda and TubeMaster 二分图、费用流

    传送门 看到这张图,是一个网格图,而且有回路限制,不难想到黑白染色. 一般来说我们对一张图黑白染色之后都是黑色点向白色点连边,但是这道题往这边想似乎就想不出建图方法了,因为"一个格子强制流满 ...

  5. 2016 ACM-ICPC China Finals #F Mr. Panda and Fantastic Beasts

    题目链接$\newcommand{\LCP}{\mathrm{LCP}}\newcommand{\suf}{\mathrm{suf}}$ 题意 给定 $n$ 个字符串 $s_1, s_2, \dots ...

  6. 2016 China Final E - Bet

    /************************************************************************* > File Name: E.cpp > ...

  7. 2016 China Final H - Great Cells

    /************************************************************************* > File Name: H.cpp > ...

  8. 2016EC Final F.Mr. Panda and Fantastic Beasts

    题目大意 \(T(1\leq T\leq42)\)组数据,给定\(n(2\leq n\leq 50000)\)个字符串\(S_{i}(n\leq\sum_{i=1}^{n}S_{i}\leq 2500 ...

  9. 2016 China Collegiate Programming Contest Final

    2016 China Collegiate Programming Contest Final Table of Contents 2016 China Collegiate Programming ...

随机推荐

  1. Jquery基本教程(背还是要背的)

    Jquery入门学习 一.简介 1.Jquery是基于JavaScript的一种框架,兼容主流浏览器,提供了dom,animate(JQ+CSS),ajax; 2.Jquery2.0后版本不支持IE6 ...

  2. ElasticStack之Logstash安装

    服务器环境 操作系统 Host:port node 1 CentOS 7.2.1511 11.1.11.127:9200 node1 2 CentOS 7.2.1511 11.1.11.128:920 ...

  3. MySQL注释符号

    今天在执行mysql语句时很奇怪为什么没有执行,查询后发现“-- ”是mysql的注释符号,不会执行的  mysql注释符有三种: 1.#... 2."-- ",注意--后面有一个 ...

  4. 微信小程序请求openid错误码40163

    通过wx.login({})方法获取到的code只能使用一次,如果需要在哎服务器端再次请求获取openid来进行校验,需要再次通过wx.login({})方法获取code 否则会报错误代码40163, ...

  5. Django配置文件解释

    """Django settings for first project. Generated by 'django-admin startproject' using ...

  6. B.Icebound and Sequence

    链接:https://ac.nowcoder.com/acm/contest/903/B 题意: Icebound hates math. But Imp loves math. One day, I ...

  7. NET Core开发

    NET Core开发 Visual Studio 2017 ASP.NET Core开发,Visual Studio 2017 已经内置ASP.NET Core 开发工具. 在选择.NET Core ...

  8. STM32空闲中断

    收发共存的思路没有经过验证!!! 空闲中断:既可以用来作为不定长接收数据帧的断帧判断/特别是DMA数据的接收,也可以用来指示中断发送的结束. 在需要发送的地方USART_ITConfig(UART5, ...

  9. linux打包文件,压缩文件

    1.打包: linux下最常用的打包程序就是tar了,使用tar程序打出来的包我们常称为tar包,tar包文件的命令通常都是以.tar结尾的.生成tar包后,就可以用其它的程序来进行压缩. 1.命令格 ...

  10. 死磕 java并发包之LongAdder源码分析

    问题 (1)java8中为什么要新增LongAdder? (2)LongAdder的实现方式? (3)LongAdder与AtomicLong的对比? 简介 LongAdder是java8中新增的原子 ...