[jzoj5307]【NOIP2017提高A組模擬8.18】偷竊

凡人不可見

不得不說,這題目真的贊(๑•̀ㅂ•́)و✧

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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章