【GCJ2008E】日程表 最小割
Google Code Jam 2008 E 日程表
【题目描述】
热情的选手Sphinny正在看新一年的日程表,并发现已经安排了很多编 程竞赛。她将这一年的每一天都用以下三种方式之一在日程表上打标记。
1.白色:这一天她将不参加竞赛。或许这一天没有预定的竞赛,或许 这一天有更重要的事情要做(生活中肯定还有其他美好的事情)。
2.蓝色:这一天她将参加一场竞赛。
3.问号:这一天有预定好的竞赛,但她还没有决定好是否参加。
为了简化问题,我们假设没有资格的概念:你不必参加一场比赛去取得另 一场比赛的参赛资格。
Sphinny生活的世界与我们的世界有所不同,那个世界里一年有n个月, 每个月恰有m天。
下面的图片是一张5个月,每个月有8天的日程表。上面有15天标记为 蓝色,5天标记了问号。

看她美丽的日程表。Sphinny认为对于每一天,有四天与它相邻(可能有 的不存在):同一个月的前一天,同一个月的后一天,前一个月的同一天,后 一个月的同一天。
Sphinny想最大化所有竞赛的喜悦值之和。一场竞赛的喜悦值的计算方式 是:
1.初始为4。
2.每有与那一天相邻的一天要参赛,喜悦值减1。(你可以认为Sphinny喜欢竞赛,但连续参赛让她感觉很累。并且出于审美的原因,在相邻 两个月的同一天参赛也不是很好。)
现在,Sphinny想计划这一年,并决定把每一个问号标记都改为白色标记 或蓝色标记。她的目标很简单,就是最大化总喜悦值。
下图是上面例子的一种解决方案。通过把2个问号标记变为蓝色标记,剩 下的3个问号标记变为白色标记,她可以得到喜悦值42。

【输入格式】
第一行一个整数T表示测试数据组数。
对于每一组数据:第一行两个整数n,m表示有n个月,每个月有m天。 之后n行每行一个长度为m的字符串,第i行第j个字符表示第i个月的第j 天的状态,“#”表示这一天被标记为蓝色,“.”表示这一天被标记为白色,"?”表示这一天被标记为问号。
【输出格式】
对于每一组数据,输出: Case #X: Y
X是第几组测试数据,Y是最大总喜悦值。
【输入样例】
2
3 3
.?.
.?.
.#.
5 8
.#...##.
.##..?..
.###.#
.# ??#.
.?.. ##
#?#...
【输出样例】
Case #1: 8
Case #2: 42
【数据范围】
对于30%的数据,1≤n,m≤5
对于60%的数据,1≤n,m≤15
对于100%的数据,1≤n,m≤50,1≤T≤100
Solution
30%乱搞暴力 60%可以状压DP 100%最小割
要求总收益最大,可以转化为 损失最小 ,然后答案就是可以获得的最大总收益-最小损失可以利用最小割来求解
考虑对方格进行黑白染色
“.”点对答案没有影响,所以不用考虑,考虑“#”“?”的相互影响即可
那么我们先预处理出$tot=\sum val[i] + \sum sc[i] $ 其中 $val[i]$表示“?”点的预期得分(4-2*四联通的“#”数),$sc[i]$表示已经确定的“#”的确定得分
那么考虑最小割建模
S连白色“?”点,容量为 $val[i]$
黑色“?”点连T,容量为 $val[i]$
相邻的黑白点,由白“?”点向黑“?”点,容量为$2$
考虑一个割,如果割的是与S相连的边,表示这个白点不变蓝,如果割与T相连,表示这个黑点不变蓝,如果割中间边,表示都变蓝
这里有个值得注意的地方,对于一个“?”点,如果他的四联通中有$>=2$个“#”点,那么这个点我们可以忽略
最后答案为$Ans=tot-mincut$
faebdc学长的标解:
初始化ans为所有问号标记都为白色标记时的喜悦值,再将ans加上问号标记个数的4倍。那么:
. 问号标记变为白色标记,ans要减4。
.问号标记变为蓝色标记,若它周围有tot个一开始就是蓝色的标记,ans要减去2*tot。
. 两个相邻的问号标记?_1和?_2都变为蓝色标记,ans要减去2。
建图时,让每一个问号标记对应着图中的一个点。考虑前两种情况,可以让每个点与源点、汇点各连一条边,流量为4和2*tot。考虑第三种情况,?_1和?_2都变为蓝色标记时,ans要减去2,可以使用下图这样的建图方式。
这样,只有相邻两个问号标记都变为蓝色标记时,连接这两个问号标记的边才会被割掉,使ans减小2。
将网格染色,相邻的格子颜色不同,就会形成二分图。一种颜色的点用?_1的连接方式,另一种颜色的点用?_2的连接方式。
ans减去求出的最大流即为答案。
标准建图
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
void Freopen() {freopen("cal.in","r",stdin); freopen("cal.out","w",stdout);}
void Fclose() {fclose(stdin); fclose(stdout);}
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXM 1000100
#define MAXN 100100
int N,M,cas,Cas;
char G[][];
struct EdgeNode{int next,to,cap;}edge[MAXM];
int head[MAXN],cnt=;
void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].cap=w;}
void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,);}
int dis[MAXN],que[MAXN<<],cur[MAXN],S,T;
bool bfs()
{
for (int i=S; i<=T; i++) dis[i]=-;
que[]=S; dis[S]=; int he=,ta=;
while (he<ta)
{
int now=que[he++];
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]==-)
dis[edge[i].to]=dis[now]+,que[ta++]=edge[i].to;
}
return dis[T]!=-;
}
int dfs(int loc,int low)
{
if (loc==T) return low;
int w,used=;
for (int i=cur[loc]; i; i=edge[i].next)
if (edge[i].cap && dis[edge[i].to]==dis[loc]+)
{
w=dfs(edge[i].to,min(low-used,edge[i].cap));
edge[i].cap-=w; edge[i^].cap+=w;
used+=w; if (edge[i].cap) cur[loc]=i;
if (used==low) return low;
}
if (!used) dis[loc]=-;
return used;
}
#define inf 0x7fffffff
int dinic()
{
int tmp=;
while (bfs())
{
for (int i=S; i<=T; i++) cur[i]=head[i];
tmp+=dfs(S,inf);
}
return tmp;
}
bool OK(int x,int y) {return (x>= && x<=N)&&(y>= && y<=M);}
int Get(int x,int y)
{
int re=;
if (OK(x-,y) && G[x-][y]=='#') re++;
if (OK(x+,y) && G[x+][y]=='#') re++;
if (OK(x,y-) && G[x][y-]=='#') re++;
if (OK(x,y+) && G[x][y+]=='#') re++;
return re;
}
int id[][],ID,col[][];
void init() {cnt=; memset(head,,sizeof(head)); ID=;}
void BuildGraph()
{
int Tot=;
init();
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
id[i][j]=++ID,col[i][j]=(i+j)&;
S=; T=ID+;
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
{
if (G[i][j]=='#') Tot+=-Get(i,j);
if (G[i][j]=='?') if (Get(i,j)<) Tot+=-*Get(i,j);
}
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
if (G[i][j]=='?')
if (col[i][j])
{
if (Get(i,j)<)
{
InsertEdge(S,id[i][j],-*Get(i,j));
if (OK(i-,j) && G[i-][j]=='?') InsertEdge(id[i][j],id[i-][j],);
if (OK(i+,j) && G[i+][j]=='?') InsertEdge(id[i][j],id[i+][j],);
if (OK(i,j-) && G[i][j-]=='?') InsertEdge(id[i][j],id[i][j-],);
if (OK(i,j+) && G[i][j+]=='?') InsertEdge(id[i][j],id[i][j+],);
}
}
else
if (Get(i,j)<) InsertEdge(id[i][j],T,-*Get(i,j));
int MaxFlow=dinic();
printf("Case #%d: %d\n",Cas-cas,Tot-MaxFlow);
}
int main()
{
Freopen();
Cas=cas=read();
while (cas--)
{
N=read(),M=read();
for (int i=; i<=N; i++)
for (int j=; j<=M; j++)
cin>>G[i][j];
BuildGraph();
}
Fclose();
return ;
}
【GCJ2008E】日程表 最小割的更多相关文章
- BZOJ 1391: [Ceoi2008]order [最小割]
1391: [Ceoi2008]order Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1509 Solved: 460[Submit][Statu ...
- BZOJ-2127-happiness(最小割)
2127: happiness(题解) Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1806 Solved: 875 Description 高一 ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- BZOJ3438 小M的作物(最小割)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=3438 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为 ...
- 最大流-最小割 MAXFLOW-MINCUT ISAP
简单的叙述就不必了. 对于一个图,我们要找最大流,对于基于增广路径的算法,首先必须要建立反向边. 反向边的正确性: 我努力查找了许多资料,都没有找到理论上关于反向边正确性的证明. 但事实上,我们不难理 ...
- bzoj1412最小割
太羞耻了,m n写反了(主要是样例n m相等) 建图方法比较高(ji)端(chu),对于可以加栅栏的地方连上1的边,然后求最小割即可 为了让代码优(suo)美(duan),我写了一个check,避免多 ...
- 【BZOJ1497】[NOI2006]最大获利 最小割
裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的 ...
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- CQOI 2016 不同的最小割
题目大意:一个无向图,求所有点对不同的最小割种类数 最小割最多有n-1个,这n-1个最小割构成一个最小割树 分治法寻找n-1个最小割.对于当前点集X,任选两点为ST做最小割,然后找出与S相连的所有点和 ...
随机推荐
- 规范化注释 VVDocumenter的使用方法
很多时候,为了快速开发,很多的技术文档都是能省则省,这个时候注释就变得异常重要,但是每次都要手动输入规范化的注释,着实也麻烦,但有了VVDocumenter,规范化的注释,主需要输入三个斜线“///” ...
- Regression analysis
Source: http://wenku.baidu.com/link?url=9KrZhWmkIDHrqNHiXCGfkJVQWGFKOzaeiB7SslSdW_JnXCkVHsHsXJyvGbDv ...
- BZOJ 1191 【HNOI2006】 超级英雄Hero
Description 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金.主持人问题准备了若干道题目,只有当选手正确回 ...
- 【MySql】C#数据库备份与还原
public static class SQLBackup { /// <summary> /// 执行Cmd命令 /// </summary> /// <param n ...
- [数据库]漫谈ElasticSearch关于ES性能调优几件必须知道的事(转)
ElasticSearch是现在技术前沿的大数据引擎,常见的组合有ES+Logstash+Kibana作为一套成熟的日志系统,其中Logstash是ETL工具,Kibana是数据分析展示平台.ES让人 ...
- Cordova - 使用Cordova开发iOS应用实战4(调用摄像头拍照,并编辑)
使用Cordova可以很方便的通过js代码来使用设备摄像头拍照,只需把camera插件添加进来即可. 一,添加camera插件 首先我们要在“终端”中进入工程所在的目录,然后运行如下命令: 1 cor ...
- saltstack安装配置(halite)
saltstack官方提供了一个简单的web UI--halite.但是给出的安装配置方法实在没法实现,在网上找了几篇博客,见文章末尾的参考链接,可以用起来了.但是功能有点简单.这篇文章记录安装配置h ...
- VS改大小写的快捷键
改成小写:Ctrl+U 改成大写:Ctrl+Shift+U 记得要选中要修改的一段英文.
- 利用Spring MVC搭建REST Service
之前写过一篇 利用JAX-RS快速开发RESTful 服务 今天来看下spring-mvc框架如何实现类似的功能: 一.pom.xml <?xml version="1.0" ...
- 细细品味Storm_Storm简介及安装
Storm是由专业数据分析公司BackType开发的一个分布式实时数据处理软件,可以简单.高效.可靠地处理大量的数据流.Twitter在2011年7月收购该公司,并于2011年9月底正式将Storm项 ...