4950: [Wf2017]Mission Improbable
Time Limit: 1 Sec Memory Limit: 1024 MBSubmit: 122 Solved: 58
[ Submit][ Status][ Discuss]
Description
那是春日里一个天气晴朗的好日子,你准备去见见你的老朋友Patrick,也是你之前的犯罪同伙。Patrick在编程竞赛
上豪赌输掉了一大笔钱,所以他需要再干一票。为此他需要你的帮助,虽然你已经金盆洗手了。你刚开始很不情愿,
因为你一点也不想再回到那条老路上了,但是你觉得听一下他的计划也无伤大雅。在附近的一个仓库里有一批货物,包含一些贵重的消费性部件,Patrick企图从中尽可能多地偷些东西出来。这意味着要找一条进去的路,弄晕安保人员,穿过各种各样的激光射线,你懂的,都是常见的抢劫技术。然而,仓库的核心装备了一套Patrick搞不定的安保系统。这也是他需要你帮助他的地方。这批货物被放置在一些巨大的立方体箱里,每个箱子的尺寸都是相同的。这些箱子堆放成许多整齐的堆,每个箱子可以表示成一个三维的网格。安保系统每个小时会用三台相机对这堆货物进行一次拍照,相机分别为:前置相机(front camera),侧置相机(side camera)和顶置相机(top camera)。前置相机的照片显示了每一行最高的那堆箱子的高度,侧置相机显示了每一列最高的那堆箱子的高度,顶置相机显示了每个位置是否存在一堆箱子。如果安保系统发现任何一张照片出现了变化,它会立即拉响警报。一旦 Patrick 进去了,他会确定每堆箱子的高度并且发给你。图1显示了一种网格可能的放置,以及每台相机会得到的视图。
![](http://www.lydsy.com/JudgeOnline/upload/201708/22.png)
图 1. 网格的高度值与对应的相机视图。
![](http://www.lydsy.com/JudgeOnline/upload/201708/33.png)
图 2. 洗劫后网格可能的高度值。
Patrick想尽可能多偷走一些箱子。由于他不能弄坏安保系统,他准备重新安排剩余每堆箱子的放置,使得下一次相
机取像时会得到相同的照片,从而骗过安保系统。在上面的例子中,他可以偷走九个箱子。图2显示了一种可能的剩余箱子的安置方案能使得安保系统认为与原安置情况相同。Patrick想请你帮他确定在保证能骗过安保系统的情况下他最多能偷走多少个箱子。你会帮他干完这最后一票么?
Input
第一行包含两个整数r(1≤r≤100)和c(1≤n≤100),分别表示网格的行数与列数。
接下来r行,每行包含c个整数,表示对应行上每堆立方体箱的高度(箱子的数量)。
所有的高度在0到10^9之间 (含边界) 。
Output
输出在不被发现的情况下最多能偷走多少箱子。
Sample Input
5 5
1 4 0 5 2
2 1 2 0 1
0 2 3 4 4
0 3 0 3 1
1 2 2 1 1
2 3
50 20 3
20 10 3
Sample Output
9
30
这题有毒
先把所有的箱子全部拿掉,再想办法放上去
①首先所有原本有箱子的格子上放回1个箱子
②然后每行、每列各选择任意一个格子放箱子,使得满足主视图侧视图要求
到这里就满足条件了,但显然不是最优解,因为当行最大值和列最大值相等的时候,只需要选择行列交叉的地方放箱子即可同时满足行列最大值要求,这样可以少放一堆
③那怎么办啊?考虑二分匹配,如果第x行和第y列最大值相等,且(x, y)上原本有箱子,那么x->y连一条边,求出最大匹配,最大匹配中的每一条边都可以为你剩下一堆箱子,全部减去就好了
注意最大值为0的情况!
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
int m, vis[105], link[105], road[105][105], a[105][105], h[105], c[105];
int Sech(int x)
{
int i;
for(i=1;i<=m;i++)
{
if(vis[i]==0 && road[x][i])
{
vis[i] = 1;
if(link[i]==0 || Sech(link[i]))
{
link[i] = x;
return 1;
}
}
}
return 0;
}
int main(void)
{
LL ans = 0;
int n, i, j;
scanf("%d%d", &n, &m);
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%d", &a[i][j]);
h[i] = max(h[i], a[i][j]);
c[j] = max(c[j], a[i][j]);
ans += max(a[i][j]-1, 0);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(h[i] && h[i]==c[j] && a[i][j]!=0)
road[i][j] = 1;
}
}
for(i=1;i<=n;i++)
{
memset(vis, 0, sizeof(vis));
Sech(i);
}
for(i=1;i<=n;i++)
ans -= max(h[i]-1, 0);
for(i=1;i<=m;i++)
ans -= max(c[i]-1, 0);
for(i=1;i<=m;i++)
{
if(link[i])
ans += max(c[i]-1, 0);
}
printf("%lld\n", ans);
return 0;
}