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】日程表 最小割的更多相关文章

  1. BZOJ 1391: [Ceoi2008]order [最小割]

    1391: [Ceoi2008]order Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1509  Solved: 460[Submit][Statu ...

  2. BZOJ-2127-happiness(最小割)

    2127: happiness(题解) Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1806  Solved: 875 Description 高一 ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. BZOJ3438 小M的作物(最小割)

    题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=3438 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为 ...

  5. 最大流-最小割 MAXFLOW-MINCUT ISAP

    简单的叙述就不必了. 对于一个图,我们要找最大流,对于基于增广路径的算法,首先必须要建立反向边. 反向边的正确性: 我努力查找了许多资料,都没有找到理论上关于反向边正确性的证明. 但事实上,我们不难理 ...

  6. bzoj1412最小割

    太羞耻了,m n写反了(主要是样例n m相等) 建图方法比较高(ji)端(chu),对于可以加栅栏的地方连上1的边,然后求最小割即可 为了让代码优(suo)美(duan),我写了一个check,避免多 ...

  7. 【BZOJ1497】[NOI2006]最大获利 最小割

    裸的最小割,很经典的模型. 建图:要求总收益-总成本最大,那么将每条弧与源点相连,流量为成本,每个收益与汇点相连,流量为收益,然后每条弧与它所能到达的收益相连,流量为inf. 与源点相连的是未被选中的 ...

  8. 二分图&网络流&最小割等问题的总结

    二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...

  9. CQOI 2016 不同的最小割

    题目大意:一个无向图,求所有点对不同的最小割种类数 最小割最多有n-1个,这n-1个最小割构成一个最小割树 分治法寻找n-1个最小割.对于当前点集X,任选两点为ST做最小割,然后找出与S相连的所有点和 ...

随机推荐

  1. 2055 [ZJOI2009]假期的宿舍

    P2055 [ZJOI2009]假期的宿舍 题目描述 学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题.比如 A 和 B 都是学校的学生,A ...

  2. chrome升级后LODOP打印插件无法使用

    今天帮朋友使用LODOP实现一个套打程序时,发现LODOP打印插件在chrome下始终无法使用.分析后发现是自己才升级了chrome,chrome新版默认是禁用npapi的,因此需要手动启用一下,启用 ...

  3. 【转】让Bootstrap 3兼容IE8浏览器

    FROM : http://www.ijophy.com/2014/05/bootstrap3-compatible-with-ie8.html 最近在研究Bootstrap(官方,Github)这个 ...

  4. 用C++和shell获取本机CPU、网卡IO、内存、磁盘等的基本信息

    用C++和shell获取本机CPU.网卡.内存.磁盘等的基本信息: 由于对C++相关的函数没多少了解,但是觉得用shell反而相对简单一些: 一.shell脚本,用来辅助C++获取主机的资源使用信息 ...

  5. C118+Osmocom-bb+Openbts搭建小型基站

    演示图片: 演示视频: 交流论坛:GsMsEc 交流Q群:

  6. 我这样理解js里的this

    关于this,是很多前端面试必考的题目,有时候在网上看到这些题目,自己试了一下,额,还真的错了!在实际开发中,也会遇到 this 的问题(虽然一些类库会帮我们处理),例如在使用一些框架的时候,例如:k ...

  7. Oracle On 、Where、Having 区别

    ON .WHERE.HAVING都能通过限制条件筛选数据,但他们的使用及其不同.下面我们来分析三者之间的区别. 1. ON 和WHERE 所有的查询都回产生一个中间临时报表,查询结果就是从返回临时报表 ...

  8. Word 打包 zip 并提供下载

    该篇博客记录Java Web项目将word打包zip并提供下载功能的实现和其中遇到的坑,方便后续自己的查看的参照. 1. 后台处理的java 方法 首先将所有的word生成到uploadword目录下 ...

  9. 求解最大矩形面积 — leetcode 85. Maximal Rectangle

    之前切了道求解最大正方形的题,题解猛戳 这里.这道题 Maximal Rectangle 题意与之类似,但是解法完全不一样. 先来看这道题 Largest Rectangle in Histogram ...

  10. 从语言到库到框架,再到API,再到标记最后到DSL语言

    计算机技术发展很快,而且越来越快,结果也是越来越复杂,那么我们到底怎么搞定复杂性并重用代码? 很明显,这是个大难题.一开始我们要解决计算问题,发展了基本的编程语言. 很快,编程语言不能满足需求,我们需 ...