不得不说,这题目真的赞(๑•̀ㅂ•́)و✧
Solution
容易想到,题意是求 在保证每行每列的最大值仍旧存在的情况下,所需要的最小砖块数。
考虑贪心,对于一个贡献更大的量的量,优先取
此处指 实际贡献 也就是说 如果该行已经被另一个取了,那么它的贡献只剩下列
所以策略在于优先选行列最大值相等的点
~~其实博主太弱不会证明 ~~╯︿╰
另外一种做法是模型转换 然后二分图匹配
截个图吧反正我看不懂绝不是不负责任
Code
二分图匹配 (来自网络 侵删)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=150;
int input(){
int f=1,s=0;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){s=s*10+c-'0';c=getchar();}
return s*f;
}
int n,m;
int side[N],fron[N];
int Link[N],mp[N][N];
bool vis[N],a[N][N];
ll sum,red;
bool find(int x){
for(int i=1;i<=m;++i)
if(!vis[i] && a[x][i]){
vis[i]=1;if(!Link[i] || find(Link[i])){Link[i]=x;return 1;}
}
return 0;
}
int main(){
n=input();m=input();
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
mp[i][j]=input();if(!mp[i][j])continue;
side[i]=max(side[i],mp[i][j]);
fron[j]=max(fron[j],mp[i][j]);
++red;sum+=mp[i][j];
}
}
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(mp[i][j] && side[i]==fron[j])a[i][j]=1;
for(int i=1;i<=n;++i){memset(vis,0,sizeof(vis));find(i);}
for(int i=1;i<=n;++i)if(side[i])red+=side[i]-1;
for(int i=1;i<=m;++i)if(fron[i] && !Link[i])red+=fron[i]-1;
printf("%lld\n",sum-red);
return 0;
}
贪心伪装正解
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define oo 2139062143
#define fo(i,x,y) for (register ll i = (x);i <= (y);++ i)
#define fd(i,x,y) for (register ll i = (x);i >= (y);-- i)
using namespace std;
typedef double db;
typedef long long ll;
ll abs(ll x) {return(((x)>=0)?(x):(-(x)));}
ll max(ll x,ll y) {return(((x)>(y))?(x):(y));}
ll min(ll x,ll y) {return(((x)<(y))?(x):(y));}
ll lowbit(ll x) {return((x)&(-x));}
const ll N = 110;
ll a[N][N];
ll mxx[N],mxy[N];
ll bz[N][N];
ll okx[N],oky[N],b[N];
ll n,m,sum,cost;
int main()
{
scanf("%lld%lld", &n, &m);
fo(i,1,n) fo(j,1,m)
{
scanf("%lld", &a[i][j]);
if (a[i][j]) sum += a[i][j];
mxx[i] = max(a[i][j],mxx[i]);
mxy[j] = max(a[i][j],mxy[j]);
}
fo(i,1,n)
{
cost += mxx[i];
bool ok = 0;
fo(j,1,m)
if (!b[j] && a[i][j] && mxy[j] == mxx[i])
{
bz[i][j] = mxx[i],ok = b[j] = 1;
break;
}
if (!ok)
fo(j,1,m)
if (a[i][j] && mxy[j] >= mxx[i])
{
bz[i][j] = mxx[i];
break;
}
}
fo(j,1,m)
if (!b[j])
{
cost += mxy[j];
fo(i,1,n)
{
if (a[i][j] && !bz[i][j] && mxy[j] <= mxx[i])
{
bz[i][j] = mxy[j];
break;
}
}
}
fo(i,1,n) fo(j,1,m)
if (a[i][j] && !bz[i][j]) ++ cost;
printf("%lld", sum - cost);
}