Golden Eggs

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 304    Accepted Submission(s): 172

Problem Description
There is a grid with N rows and M columns. In each cell you can choose to put a golden or silver egg in it, or just leave it empty. If you put an egg in the cell, you will get some points which depends on the color of the egg. But for every pair of adjacent eggs with the same color, you lose G points if there are golden and lose S points otherwise. Two eggs are adjacent if and only if there are in the two cells which share an edge. Try to make your points as high as possible.
 
Input
The first line contains an integer T indicating the number of test cases.
There are four integers N, M, G and S in the first line of each test case. Then 2*N lines follows, each line contains M integers. The j-th integer of the i-th line Aij indicates the points you will get if there is a golden egg in the cell(i,j). The j-th integer of the (i+N)-th line Bij indicates the points you will get if there is a silver egg in the cell(i,j).

Technical Specification
1. 1 <= T <= 20
2. 1 <= N,M <= 50
3. 1 <= G,S <= 10000
4. 1 <= Aij,Bij <= 10000

 
Output
For each test case, output the case number first and then output the highest points in a line.
 
Sample Input
2
2 2 100 100
1 1
5 1
1 4
1 1
1 4 85 95
100 100 10 10
10 10 100 100
 
Sample Output
Case 1: 9
Case 2: 225
 
Author
hanshuai
 
Source
 
Recommend
lcy
 

还是SAP快:

大致题意:
    给出一块n*m的区域,已知区域中的每个格子都可以放金蛋或者是银弹,已知每个格子放金蛋或者是放银弹时可以得到的收益,分别用矩阵map1[][],map2[][]表示。如果相邻的两个格子放的蛋相同的话会扣去一定的收益,金蛋的话会扣去g,银弹s。求收益的最大值是多少。
 
大致思路:
    首先,对于某个确定的位置,只能选择金蛋或者银弹的其中一个放上去,从这里可以想到和二分图最大点权独立集有关。其次,如果相邻的位置放的蛋相同的话需要付出一定的花费这个又和hdu 3657:Game有些许相似之处。所以我们这么构图:
 
按照黑白染色把矩阵中的位置分为A,B两个集合,每个集合中的位置拆为k,k'两个点。对于A集合,从源点向k连边,容量为它放金蛋是的收获,从k再向k'连边容量设为inf,从k'连到汇点,容量为其放银弹时的收益。这样设的目的就是为了使得割必须在源点到k或者k'到汇点上。   
对于B集合,我们做一些改变,把从源点到k的容量设为放银弹的收益,k'到汇点的容量设为其放金蛋的收益,k和k'之间容量为inf的边不变。至于为什么看下一步。
然后再接下来一步加边就是关键了!我们知道如果A集合中的金蛋和B集合中的金蛋相邻的话会付出一定的话费,为了表示设A集合中的某位置a是金蛋,我们会连接源点->a。为了表示B集合中位置b是金蛋的,我们会连接b'->汇点。好的,在这里我们假设b位置和a相邻。为了表示a位置和b位置同时放金蛋需要G的花费,我们连接a->b'并把其容量设为G,对于银弹我们做同样的处理。至于为什么,好好把hdu3567刷掉就全明白了
接下来,用所有的map1[i][j]+map2[i][j]-最小割得到的就是答案。
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue> using namespace std; const int VM=;
const int EM=;
const int INF=0x3f3f3f3f; struct Edge{
int to,nxt;
int cap;
}edge[EM<<]; int n,m,G,S,cnt,head[VM],src,des,map1[][],map2[][];
int dep[VM],gap[VM],cur[VM],aug[VM],pre[VM]; void addedge(int cu,int cv,int cw){
edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu];
head[cu]=cnt++;
edge[cnt].to=cu; edge[cnt].cap=; edge[cnt].nxt=head[cv];
head[cv]=cnt++;
} int SAP(int n){
int max_flow=,u=src,v;
int id,mindep;
aug[src]=INF;
pre[src]=-;
memset(dep,,sizeof(dep));
memset(gap,,sizeof(gap));
gap[]=n;
for(int i=;i<=n;i++)
cur[i]=head[i]; // 初始化当前弧为第一条弧
while(dep[src]<n){
int flag=;
if(u==des){
max_flow+=aug[des];
for(v=pre[des];v!=-;v=pre[v]){ // 路径回溯更新残留网络
id=cur[v];
edge[id].cap-=aug[des];
edge[id^].cap+=aug[des];
aug[v]-=aug[des]; // 修改可增广量,以后会用到
if(edge[id].cap==) // 不回退到源点,仅回退到容量为0的弧的弧尾
u=v;
}
}
for(int i=cur[u];i!=-;i=edge[i].nxt){
v=edge[i].to; // 从当前弧开始查找允许弧
if(edge[i].cap> && dep[u]==dep[v]+){ // 找到允许弧
flag=;
pre[v]=u;
cur[u]=i;
aug[v]=min(aug[u],edge[i].cap);
u=v;
break;
}
}
if(!flag){
if(--gap[dep[u]]==) // gap优化,层次树出现断层则结束算法
break;
mindep=n;
cur[u]=head[u];
for(int i=head[u];i!=-;i=edge[i].nxt){
v=edge[i].to;
if(edge[i].cap> && dep[v]<mindep){
mindep=dep[v];
cur[u]=i; // 修改标号的同时修改当前弧
}
}
dep[u]=mindep+;
gap[dep[u]]++;
if(u!=src) // 回溯继续寻找允许弧
u=pre[u];
}
}
return max_flow;
} int main(){ //freopen("input.txt","r",stdin); int t,cases=;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&m,&G,&S);
cnt=;
memset(head,-,sizeof(head));
src=; des=n*m*+;
int sum=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
scanf("%d",&map1[i][j]);
sum+=map1[i][j];
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
scanf("%d",&map2[i][j]);
sum+=map2[i][j];
}
int tmp;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
tmp=(i-)*m+j;
if((i+j)%==){
addedge(src,tmp,map1[i][j]);
addedge(tmp,tmp+n*m,INF);
addedge(tmp+n*m,des,map2[i][j]); if(i>) addedge(tmp,tmp-m+n*m,G);
if(i<n) addedge(tmp,tmp+m+n*m,G);
if(j>) addedge(tmp,tmp-+n*m,G);
if(j<m) addedge(tmp,tmp++n*m,G); }else{
addedge(src,tmp,map2[i][j]);
addedge(tmp,tmp+n*m,INF);
addedge(tmp+n*m,des,map1[i][j]); if(i>) addedge(tmp,tmp-m+n*m,S);
if(i<n) addedge(tmp,tmp+m+n*m,S);
if(j>) addedge(tmp,tmp-+n*m,S);
if(j<m) addedge(tmp,tmp++n*m,S);
}
}
}
printf("Case %d: %d\n",++cases,sum-SAP(des+));
}
return ;
}
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue> using namespace std; const int VM=;
const int EM=;
const int INF=0x3f3f3f3f; struct Edge{
int to,nxt;
int cap;
}edge[EM<<]; int n,m,G,S,cnt,head[VM],src,des;
int map1[][],map2[][],dep[VM]; //dep[i]表示当前点到起点src的层数 void addedge(int cu,int cv,int cw){
edge[cnt].to=cv; edge[cnt].cap=cw; edge[cnt].nxt=head[cu];
head[cu]=cnt++;
edge[cnt].to=cu; edge[cnt].cap=; edge[cnt].nxt=head[cv];
head[cv]=cnt++;
} int BFS(){ // 重新建图(按层数建图)
queue<int> q;
while(!q.empty())
q.pop();
memset(dep,-,sizeof(dep));
dep[src]=;
q.push(src);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-;i=edge[i].nxt){
int v=edge[i].to;
if(edge[i].cap> && dep[v]==-){ // 如果可以到达且还没有访问
dep[v]=dep[u]+;
q.push(v);
}
}
}
return dep[des]!=-;
} int DFS(int u,int minx){ // 查找路径上的最小的流量
if(u==des)
return minx;
int tmp;
for(int i=head[u];i!=-;i=edge[i].nxt){
int v=edge[i].to;
if(edge[i].cap> && dep[v]==dep[u]+ && (tmp=DFS(v,min(minx,edge[i].cap)))){
edge[i].cap-=tmp; //正向减少
edge[i^].cap+=tmp; //反向增加
return tmp;
}
}
dep[u]=-; //这一句作用无穷大,不在TLE。。。。。。。。。。。
return ;
} int Dinic(){
int ans=,tmp;
while(BFS()){
while(){
tmp=DFS(src,INF);
if(tmp==)
break;
ans+=tmp;
}
}
return ans;
} int main(){ //freopen("input.txt","r",stdin); int t,cases=;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&m,&G,&S);
cnt=;
memset(head,-,sizeof(head));
src=; des=n*m*+;
int sum=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
scanf("%d",&map1[i][j]);
sum+=map1[i][j];
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
scanf("%d",&map2[i][j]);
sum+=map2[i][j];
}
int tmp;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
tmp=(i-)*m+j;
if((i+j)%==){
addedge(src,tmp,map1[i][j]);
addedge(tmp,tmp+n*m,INF);
addedge(tmp+n*m,des,map2[i][j]);
//
if(i!=)addedge(tmp,tmp-m+n*m,G);
if(i!=n)addedge(tmp,tmp+m+n*m,G);
if(j!=)addedge(tmp,tmp-+n*m,G);
if(j!=m)addedge(tmp,tmp++n*m,G);
//
}
else{
addedge(src,tmp,map2[i][j]);
addedge(tmp,tmp+n*m,INF);
addedge(tmp+n*m,des,map1[i][j]);
if(i!=)addedge(tmp,tmp-m+n*m,S);
if(i!=n)addedge(tmp,tmp+m+n*m,S);
if(j!=)addedge(tmp,tmp-+n*m,S);
if(j!=m)addedge(tmp,tmp++n*m,S);
}
}
}
printf("Case %d: %d\n",++cases,sum-Dinic());
}
return ;
}

HDU 3820 Golden Eggs (SAP | Dinic)的更多相关文章

  1. HDU 3820 Golden Eggs( 最小割 奇特建图)经典

    Golden Eggs Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. HDU 3820 Golden Eggs

    http://acm.hdu.edu.cn/showproblem.php?pid=3820 题意:n*m的格子,每个格子放金蛋或银蛋,每个格子的金蛋和银蛋都有一个对应的点权,如果有两个金蛋相连,则需 ...

  3. HDU3820 Golden Eggs(最小割)

    题目大概说给一个n*m的格子,每个格子放金蛋或银蛋都会得到不同的价值,当然也可以不放,不过如果存在相邻的两个格子都是金蛋会损失价值g,都是银则损失s.问能得到的最大价值. 有点像二者选一的最小割模型, ...

  4. HDU 5860 Death Sequence(死亡序列)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  5. HDU 5877 Weak Pair(弱点对)

    HDU 5877 Weak Pair(弱点对) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Jav ...

  6. HDU 5813 Elegant Construction(优雅建造)

    HDU 5813 Elegant Construction(优雅建造) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65 ...

  7. HDU 5818 Joint Stacks(联合栈)

    HDU 5818 Joint Stacks(联合栈) Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Ja ...

  8. HDU 2222 Keywords Search(查询关键字)

    HDU 2222 Keywords Search(查询关键字) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K ...

  9. HDU 3549 Flow Problem(最大流)

    HDU 3549 Flow Problem(最大流) Time Limit: 5000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/ ...

随机推荐

  1. 转: linux进程地址图解

    http://www.cnblogs.com/clover-toeic/p/3754433.html

  2. maven 添加jar到中央/远程仓库

    maven 添加jar到中央/远程仓库 开源中国 发表于 2014-08-23 00:08:00 commond: mvn deploy:deploy-file -DgroupId=com.tima. ...

  3. iOS SDK 从配置文件里读SDK。转化成class 可同时加载多个SDK

    首先在工程中加入XXX  plist 配置文件. 然后在key 输入名字比如allsdk  value 里填写.a 文件的名字 NSString *plistPath = [[NSBundle mai ...

  4. linux加入windows域

    http://www.redhat.com/rhecm/rest-rhecm/jcr/repository/collaboration/jcr:system/jcr:versionStorage/36 ...

  5. Multipathing for Software iSCSI

    see also:http://www.vmware.com/files/pdf/techpaper/vmware-multipathing-configuration-software-iSCSI- ...

  6. linux2.6.30.4内核移植(6)——移植应用程序hello world常见的错误:-bin/sh ./hello not found

    通常在开发板上搭建好开发平台后,我们会试着移植一个最简单的应用程序Hello world来测试一下.初次尝试,我们经常会碰到的问题就是,在开发板上运行./hello的时候出错:-bin/sh ./he ...

  7. ACID、Data Replication、CAP与BASE

    ACID 在传数据库系统中,事务具有ACID 4个属性. (1) 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行. (2) 一致性(Consiste ...

  8. Memcached常用命令及使用说明——netcat

    数据存储(假设key为test,value为12345) printf "set test 0 0 5\r\n12345\r\n" | nc 127.0.0.1 12000 STO ...

  9. achartengine(Google给android提供的画图工具包)的介绍和使用

    AChartEngine(ACE)是Google为Android提供的一个开源绘制工具包.它集成了绘制多种图形的功能:折线图.散点图.气泡图.柱状图.饼图.仪表图等图形. 下载地址:http://do ...

  10. Linux(CentOS6.X)安装mysql

    首先执行rpm -qa|grep -i mysql检查一下是否已经安装过mysql mysql-libs-5.1.73-5.el6_6.x86_64 可见已经安装了库文件,应该先卸载,不然会出现覆盖错 ...