【AtCoder Regular Contest 092】C.2D Plane 2N Points(匈牙利算法/tuple+set 贪心)

原题链接
题意:给两个长度为n的序列的坐标,分别为(Ai,Bi),(Ci,Di),求最多有多少对坐标满足Ai<Ci并且Bi<Di。

分析:将满足题中条件的坐标对的下标(i,j)存入vector,然后就是匈牙利模板
复杂度:O(n*m) n RT,m为构成的坐标对的数量
模板解释:http://blog.csdn.net/dark_scope/article/details/8880547
可参见:http://blog.csdn.net/feng_zhiyu/article/details/79309746
匈牙利算法
代码:

#include <bits/stdc++.h>
using namespace std;

#define mem(a,n) memset(a,n,sizeof(a))
#define memc(a,b) memcpy(a,b,sizeof(b))
#define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n)
#define pb push_back
#define IO ios::sync_with_stdio(false)
#define fre freopen("in.txt","r",stdin)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
typedef unsigned long long ull;
const double PI=acos(-1.0);
const double E=2.718281828459045;
const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int MOD=1e3;
const int N=1e2+5;
const ll maxn=2e5+5;
const int dir[4][2]= {-1,0,1,0,0,-1,0,1};

int n,m;
int a[N],b[N],c[N],d[N];
int match[N];
bool vis[N];
vector<int> g[N];
bool dfs(int u)
{
    for(auto v:g[u])
    {
        if(vis[v])
            continue;
        vis[v]=1;
        if(match[v]==-1||dfs(match[v]))
        {
            match[v]=u;
            return true;
        }
    }
    return false;
}
void init()
{
    rep(i,0,n+1) g[i].clear();
}
void solve()
{
    int ans=0;
    mem(match,-1);
    rep(i,1,n+1)
    {
        mem(vis,0);
        if(dfs(i))
            ans++;
    }
    cout<<ans<<endl;
}
int main()
{
    IO;
    cin>>n;
    init();
    rep(i,1,n+1) cin>>a[i]>>b[i];
    rep(i,1,n+1) cin>>c[i]>>d[i];
    rep(i,1,n+1)
    {
        rep(j,1,n+1)
        {
            if(a[i]<=c[j]&&b[i]<=d[j])
                g[i].pb(j);
        }
    }
    solve();
    return 0;
}

好用的C++ tuple 操作解决了为啥写一个普通的贪心不能得到AC的答案。
学习了。
tuple用法:http://blog.csdn.net/feng_zhiyu/article/details/79597824

贪心
tuple实际上相当于结构体。
【结构体实现】

#include <bits/stdc++.h>
using namespace std;

#define mem(a,n) memset(a,n,sizeof(a))
#define memc(a,b) memcpy(a,b,sizeof(b))
#define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n)

struct Node
{
    int a,b,flag;
    bool operator < (const Node& m)const
    {
        if(a!=m.a) return a<m.a;
        else if(b!=m.b) return b<m.b;
        else return flag<m.flag;
    }
}a[N];
int n;
set<int>st;
void solve()
{
    st.clear();
    int ans=0;
    for(int i=0;i<2*n;i++)
    {
        int flag=a[i].flag;
        if(!flag)
        {
            st.insert(a[i].b);
        }
        else
        {
            auto it=st.lower_bound(a[i].b);
            if(it!=st.begin())
            {
                st.erase(--it);
                ans++;
            }
        }
    }
    cout<<ans<<endl;
}
int main()
{
    while(cin>>n)
    {
        rep(i,0,n)
        {
            cin>>a[i].a>>a[i].b;
            a[i].flag=0;
        }
        rep(i,n,2*n)
        {
            cin>>a[i].a>>a[i].b;
            a[i].flag=1;
        }
        sort(a,a+2*n);
        solve();
    }
    return 0;
}

【tuple实现】
复杂度: O(nlogn)
代码:

#include <bits/stdc++.h>
using namespace std;

#define mem(a,n) memset(a,n,sizeof(a))
#define memc(a,b) memcpy(a,b,sizeof(b))
#define rep(i,a,n) for(int i=a;i<n;i++) ///[a,n)
#define pb push_back
#define mkp make_pair
#define mkt make_tuple
#define IO ios::sync_with_stdio(false)
#define fre freopen("in.txt","r",stdin)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
typedef unsigned long long ull;
const double PI=acos(-1.0);
const double E=2.718281828459045;
const double eps=1e-8;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int MOD=1e3;
const int N=1e2+5;
const ll maxn=2e5+5;
const int dir[4][2]= {-1,0,1,0,0,-1,0,1};
int n;
vector<tuple<int,int,int> >vec;
set<int>st;

void solve()
{
    int ans=0;
    for(auto v: vec)
    {
        int x,y,c;
        tie(x,y,c)=v;
        if(c == 0)
        {
            st.insert(y);
        }
        else
        {
            auto it = st.lower_bound(y);
            if(it != st.begin())
            {
                ///cout<<(*it);
                st.erase(--it);///每次消除的都是当前位置前的一个坐标对,即set内的点,这样也保证是最优的
                ans++;
                ///cout<<"  ans="<<ans<<endl;
            }
        }
    }
    cout<<ans<<endl;
}
void init()
{
    vec.clear();
    st.clear();
}
int main()
{
    //fre;
    IO;
    while(cin>>n)
    {
        init();
        rep(i,0,n)
        {
            int a,b;
            cin>>a>>b;
            vec.pb(mkt(a,b,0));
        }
        rep(i,0,n)
        {
            int c,d;
            cin>>c>>d;
            vec.pb(mkt(c,d,1));
        }
        sort(vec.begin(),vec.end());
        /*for(int i=0; i<vec.size(); i++)
        {
            int x,y,c;
            tie(x,y,c)=vec[i];
            cout<<x<<" "<<y<<" "<<c<<endl;
        }*/
        solve();
    }
    return 0;
}
/**
3
2 0
3 1
1 3
4 2
0 4
5 5

3
0 0
1 1
5 2
2 3
3 4
4 5

2
2 2
3 3
0 0
1 1

5
0 0
7 3
2 2
4 8
1 6
8 5
6 9
5 4
9 1
3 7

5
0 0
1 1
5 5
6 6
7 7
2 2
3 3
4 4
8 8
9 9
**/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值