P6931 [ICPC2017 WF]Mission Improbable
P6931 [ICPC2017 WF]Mission Improbable
给定一个 r \times cr×c 的平面,在上面摆有一些箱子。我们可以得到他的三视图(如下图,左边矩阵上的值为平面上每一位摆放的箱子个数,右边三个视图为正视图,俯视图,左视图):
你可以拿走一些箱子,和重新排列这些箱子的位置,你想知道,最多能拿走多少个箱子,使得这些箱子重新排列后正视图,俯视图,左视图不变?
比如上面这个例子,下面这种拿走 99 个箱子后的重新排列方式也是可以的:
1 \le r,c \le 1001≤r,c≤100,平面上每一个位置的箱子个数在 [0,10^9][0,10
9
] 内。
エラー発生:边数应该是\(maxn * maxn\) 的。。 开小了查到半夜 哇巨蠢
Solution
贪心加二分图匹配
首先我们满足俯视图要求, 在有格子的地方全放上1先
贪心, 每一行/每一列, 我们只需要堆一次最高的箱子就行了
进一步贪心, 我们想让某一竖的箱子, 即对长的最大值产生贡献, 又对宽的最大值产生贡献。
那么跑一次二分图匹配, 看一下哪行哪列的箱子可以对应一下, 并且交点处满足俯视图可以放箱子, 连边跑匈牙利就行
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
LL out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const LL maxn = 110;
LL head[maxn * 2],nume = 1;
struct Node{
LL v,dis,nxt;
}E[maxn * maxn];
void add(LL u,LL v,LL dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
LL x, y;
LL map[maxn][maxn];
LL x_max[maxn], y_max[maxn];
LL used[maxn * 2], mat[maxn * 2];
bool match(LL u){//二分图匹配
for(LL i = head[u];i;i = E[i].nxt){
LL v = E[i].v;
if(!used[v]){
used[v] = 1;
if(!mat[v] || match(mat[v])){
mat[v] = u;
mat[u] = v;
return 1;
}
}
}
return 0;
}
void Hungary(){
REP(i, 1, x){
if(!mat[i]){
memset(used, 0, sizeof(used));
match(i);
}
}
}
LL ans;
void init(){
x = RD(), y = RD();
REP(i, 1, x)REP(j, 1, y){
map[i][j] = RD();
if(map[i][j] != 0)ans += map[i][j] - 1;//满足俯视图,贪心全拿走
}
REP(i, 1, x)REP(j, 1, y)x_max[i] = max(x_max[i], map[i][j]);
REP(i, 1, y)REP(j, 1, x)y_max[i] = max(y_max[i], map[j][i]);
REP(i, 1, x){
REP(j, 1, y){
if(x_max[i] == y_max[j] && map[i][j] != 0 && x_max[i] != 0)
add(i, maxn + j + 1, 1);
}
}
}
void work(){
Hungary();
REP(i, 1, y)
if(y_max[i])//保证下加的1
ans -= y_max[i] - 1;//先把竖着的放上去
REP(i, 1, x){
if(!mat[i] && x_max[i])
ans -= x_max[i] - 1;
}
cout<<ans<<endl;
}
int main(){
init();
work();
return 0;
}