【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相连的所有点和 ...
随机推荐
- PAT 1031. 查验身份证(15)
一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8, ...
- Entity Framework连接Mysql数据库并生成Model和DAL层
Entity Framework (EF,ADO.NET Entity Framework)是微软官方提供的.NET平台的ORM框架.相比于LINQ TO SQL,EF框架具有很明显的优势: EF框架 ...
- [Azure] 使用 Azure 快速搭建 Redis 服务器
Redis相信玩开源,大数据的朋友们并不陌生,大家最熟悉的使用者就是新浪微博,微博的整体数据缓存都是基于Redis的,而新浪对Redis的使用也非常深,据说是一组64G内存的Redis集群.前段时间我 ...
- [转]ReactPHP── PHP版的Node.js
FROM : http://www.csdn.net/article/2015-10-12/2825887 摘要:ReactPHP作为Node.js的PHP版本.在实现思路,使用方法,应用场景上的确有 ...
- 写个PHP框架吧
肯定会问:现在的PHP框架那么多了,为什么还要写一个PHP框架呢? 1.时代:PHP7来了,现在的所有框架都是基于PHP5.x的.到时候PHP7正式推广出来,现有的框架都不能发挥PHP7的最大性能优势 ...
- JS之获取属性总结
嗨,我是沐晴,今天来说说JS中关于获取属性的一些方法和区别.闲话不说,来正题. 首先什么是属性呢,比如input标签,标签中的value id type style等,这些就是属性.我们JS获取属性一 ...
- 在Windows上将ReactNative集成到现有的Android项目
React Natvie的官方文档的 Integrating with Existing Apps 已经很详细地教我们如何将React Natvie集成到现在的Android项目.我根据官方文档的步骤 ...
- 仿造slither.io第一步:先画条蛇
前言 最近 slither.io 貌似特别火,中午的时候,同事们都在玩,包括我自己也是玩的不亦乐乎. 好久好久没折腾过canvas相关的我也是觉得是时候再折腾一番啦,所以就试着仿造一下吧.楼主也没写过 ...
- .Net分布式异常报警系统-项目介绍
后台管理 首页统计的是当天每个时段的异常数量, 使用的是echarts组件, 红框所示, 可以选择不同的系统进行查看. 得益于echarts的强大功能, 你可以使用柱状图来查看. 站 ...
- 吉特仓库管理系统-.SQL Server 2012 升级企业版
随着业务数据的不断增大,单表的数量已经上亿,查询的数据越来越慢,所以考虑到将数据库表分区,同时也将数据库升级到SQL Server 2012. 当时没有考虑更多,在服务器上安装了 SQL Server ...