zoukankan      html  css  js  c++  java
  • Codeforces 1487E

    Educational Codeforces Round 104 (Rated for Div. 2) E. Cheap Dinner


    题意

    给定(n_1)第一道菜的价格(a_i)(n_2)第二道菜的价格(b_i)(n_3)饮料的价格(c_i)(n_4)甜点的价格(d_i)

    (m_1)种组合((x_i,y_i)),描述编号为(x_i)第一道菜与编号为(y_i)第二道菜不能搭配

    (m_2)种组合((x_i,y_i)),描述编号为(x_i)第二道菜与编号为(y_i)饮料不能搭配

    (m_3)种组合((x_i,y_i)),描述编号为(x_i)饮料与编号为(y_i)甜点不能搭配

    问是否能够每种种类的食物都分别挑选一种,它们可以互相搭配且总花费最小


    限制

    (1le n_1,n_2,n_3,n_4le 150000)

    (1le a_i,b_i,c_i,d_ile 10^8)

    (1le m_1,m_2,m_3le 200000)




    思路

    很容易想到是费用流的模板题,但费用流会出现(n^2)条边,这题显然不可行

    由于每种限制仅针对两种种类的食物,所以可以想到拆成三部分的二分图来做(当然不是二分图匹配)


    我们可以先处理第二道菜

    原本(b_i)表示的是“编号为(i)第二道菜的价格”

    我们可以将({a})引入,从而让(b_i)表示“编号为(i)第二道菜与某一种第一道菜搭配所能得到的最小花费”

    (b_i=b_i+min{a_j}),其中(a_j)(b_i)能够搭配

    处理好(b_i)后,接下来处理饮料时

    原本(c_i)表示的是“编号为(i)饮料的价格”

    引入({b}),从而让(c_i)表示“编号为(i)饮料与其所能搭配的(b_i)相加后,能得到的最小花费”

    (c_i=c_i+min{b_j}),其中(b_j)(c_i)能够搭配

    (d_i)同理,最终表示“编号为(i)甜点与其所能搭配的(c_i)相加后,能得到的最小花费”

    显而易见,答案就是(d_i)中的最小值


    以将({a})引入(b_i)为例

    如果我们想求出(b_i=b_i+min{a_j}),其中(a_j)(b_i)能够搭配

    最简便的方法就是枚举所有(a_j),但这样的时间复杂度就会来到(O(n^2)),显然不可行

    我们可以将数据存入结构体,记录原本的编号以及价格,将({a})进行排序

    我们可以将所有不合法的搭配((x,y))存进set容器中,由于是对每个(b_i)找出最小的(a_j),所以往编号为(y)的set容器内插入值(x),表示({b})中的(y)不能与({a})中的(x)进行搭配

    然后我们按顺序遍历排序后的({a}),每次在编号为(i)的set容器中二分查找是否存在一个值为(j)的元素

    如果不存在,说明此时的(b_i)(a_j)能够进行搭配,由因为保证了(a_j)是目前的最小值,所以直接让(b_i=b_i+a_j)即可,其后结束此次遍历

    这种方法的时间复杂度为(O(nlogm))

    ({b})引入(c_i),将({c})引入(d_i)同理,详见代码注释




    代码

    (560ms/4000ms)

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int maxn=150050;
    
    struct node
    {
        int id,val;
        bool operator < (const node& a) const
        {
            return val<a.val;
        }
    }a[maxn],b[maxn],c[maxn],d[maxn];
    
    int n1,n2,n3,n4;
    
    set<int> v1[maxn],v2[maxn],v3[maxn];
    
    void input()
    {
        cin>>n1>>n2>>n3>>n4;
        rep(i,1,n1)
            cin>>a[i].val,a[i].id=i;
        rep(i,1,n2)
            cin>>b[i].val,b[i].id=i;
        rep(i,1,n3)
            cin>>c[i].val,c[i].id=i;
        rep(i,1,n4)
            cin>>d[i].val,d[i].id=i;
        
        int m1,m2,m3;
        cin>>m1;
        while(m1--)
        {
            int a,b;
            cin>>a>>b;
            v1[b].insert(a); //往编号为b的容器内插入a
        }
        cin>>m2;
        while(m2--)
        {
            int a,b;
            cin>>a>>b;
            v2[b].insert(a);
        }
        cin>>m3;
        while(m3--)
        {
            int a,b;
            cin>>a>>b;
            v3[b].insert(a);
        }
    }
    
    void solve()
    {
        input();
        
        sort(a+1,a+1+n1); //对{a}进行排序
        
        rep(i,1,n2) //遍历所有bi
        {
            bool flag=false;
            rep(j,1,n1) //对于每一个bi,遍历排完序后的{a}
            {
                if(v1[i].find(a[j].id)==v1[i].end()) //如果aj与bi能够搭配
                {
                    b[i].val=min(a[j].val+b[i].val,INF); //直接相加即可,注意与无穷大取小,方便数据处理
                    flag=true;
                    break; //找到之后就可以直接跳出此次遍历
                }
            }
            if(!flag)
                b[i].val=INF; //如果不存在搭配,将其标记为无穷大
        }
        
        sort(b+1,b+1+n2); //下同
        
        rep(i,1,n3)
        {
            bool flag=false;
            rep(j,1,n2)
            {
                if(v2[i].find(b[j].id)==v2[i].end())
                {
                    c[i].val=min(b[j].val+c[i].val,INF);
                    flag=true;
                    break;
                }
            }
            if(!flag)
                c[i].val=INF;
        }
        
        sort(c+1,c+1+n3);
        
        rep(i,1,n4)
        {
            bool flag=false;
            rep(j,1,n3)
            {
                if(v3[i].find(c[j].id)==v3[i].end())
                {
                    d[i].val=min(c[j].val+d[i].val,INF);
                    flag=true;
                    break;
                }
            }
            if(!flag)
                d[i].val=INF;
        }
        
        sort(d+1,d+1+n4);
        
        if(d[1].val==INF)
            cout<<"-1
    ";
        else
            cout<<d[1].val<<'
    ';
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        solve();
        return 0;
    }
    

    https://blog.csdn.net/qq_36394234/article/details/113821354

  • 相关阅读:
    细说 ASP.NET Cache 及其高级用法【转】
    类变量和实例变量的区别是什么?
    【转】细说Cookie
    【转】细说 Form (表单)
    PHP API中,MYSQL与MYSQLI的持久连接区别
    Extending_and_embedding_php翻译
    linux常见面试题及答案
    手机辐射查询
    php5.3 PHP5.4 PHP5.5 新特性/使用PHP5.5要注意的
    sqoop安装遇到的问题
  • 原文地址:https://www.cnblogs.com/stelayuri/p/14405916.html
Copyright © 2011-2022 走看看