• 2019-2020 ACM-ICPC Brazil Subregional Programming Contest G. Getting Confidence (最小费用最大流)


    2019-2020 ACM-ICPC Brazil Subregional Programming Contest G. Getting Confidence


    题意

    给定一个(n imes n)的图,每个点有一个正整数(V)

    要求构造出一个排列({P}),使得所有的(V_{P_i,i})相乘的结果最大,输出这个排列

    换句话说,也就是选出(n)个数字,每行每列只能选一个,且数字相乘结果最大,最后从左到右输出每个数字的行号


    限制

    (1le nle 100)

    (1le V_{i,j}le 100)




    思路

    根据每行每列只能选一个这个条件,明显可以将行与列拆点

    要求相乘结果最大,换言之对于所有数取对数后,相加的结果应为最大

    于是就可以直接套最小费用最大流跑一遍

    源点向所有行点连边,流量为(1)费用为(0),表示每个行点只能选择一次

    所有列点向汇点连边,流量为(1)费用为(0),表示每个列点只能选择一次

    每个行点(i)向每个列点(j)连边,流量为(1)费用为(-log V_{i,j}),表示这种组合产生的花费,取反以达到求最大费用的结果

    跑完整张图后,遍历与行点相连的残量网络上的边,如果某条边流量为(0)即代表被使用过,将其与连向的列点组合,最后输出答案




    程序

    (46ms/1000ms)

    // StelaYuri
    //#include<ext/pb_ds/assoc_container.hpp>
    //#include<ext/pb_ds/hash_policy.hpp>
    #include<bits/stdc++.h>
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    #define pb push_back
    #define eb emplace_back
    #define mst(a,b) memset(a,b,sizeof(a))
    using namespace std;
    //using namespace __gnu_pbds;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> P;
    const int INF=0x3f3f3f3f;
    const ll LINF=0x3f3f3f3f3f3f3f3f;
    const double eps=1e-12;
    const double PI=acos(-1.0);
    const double angcst=PI/180.0;
    const ll mod=998244353;
    ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
    ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
    ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
    ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}
    
    const int maxn=233;
    
    struct MCMF {
        struct E {
            int from, to, cap;
            double v;
            E() {}
            E(int f, int t, int cap, double v) : from(f), to(t), cap(cap), v(v) {}
        };
        int n, m, s, t;
        vector<E> edges;
        vector<int> G[maxn];
        bool inq[maxn];
        double dis[maxn];
        int pre[maxn], a[maxn];
        void init(int _n, int _s, int _t) {
            n = _n; s = _s; t = _t;
            for (int i = 0; i <= n; i++)
                G[i].clear();
            edges.clear();
            m = 0;
        }
        void add(int from, int to, int cap, double cost) {
            edges.emplace_back(from, to, cap, cost);
            edges.emplace_back(to, from, 0, -cost);
            G[from].push_back(m++);
            G[to].push_back(m++);
        }
        bool spfa() {
            for (int i = 0; i <= n; i++) {
                dis[i] = 1e9;
                pre[i] = -1;
                inq[i] = false;
            }
            dis[s] = 0, a[s] = 1e9, inq[s] = true;
            queue<int> Q; Q.push(s);
            while (!Q.empty()) {
                int u = Q.front(); Q.pop();
                inq[u] = false;
                for (int& idx: G[u]) {
                    E& e = edges[idx];
                    if (e.cap && dis[e.to] > dis[u] + e.v) {
                        dis[e.to] = dis[u] + e.v;
                        pre[e.to] = idx;
                        a[e.to] = min(a[u], e.cap);
                        if (!inq[e.to]) {
                            inq[e.to] = true;
                            Q.push(e.to);
                        }
                    }
                }
            }
            return pre[t] != -1;
        }
        double solve() {
            int flow = 0;
            double cost = 0;
            while (spfa()) {
                flow += a[t];
                cost += a[t] * dis[t];
                int u = t;
                while (u != s) {
                    edges[pre[u]].cap -= a[t];
                    edges[pre[u] ^ 1].cap += a[t];
                    u = edges[pre[u]].from;
                }
            }
            return cost;
        }
    }f;
    
    int n;
    double v[110][110];
    
    void solve()
    {
        cin>>n;
        rep(i,1,n)
            rep(j,1,n)
            {
                cin>>v[i][j];
                v[i][j]=log(v[i][j]);
            }
        f.init(202,201,202);
        rep(i,1,n)
        {
            f.add(201,i,1,0);
            f.add(i+100,202,1,0);
        }
        rep(i,1,n)
            rep(j,1,n)
                f.add(i,j+100,1,-v[i][j]);
        f.solve();
        int ans[105];
        rep(i,1,n)
        {
            for(int &id:f.G[i])
            {
                if(f.edges[id].cap==0)
                {
                    ans[f.edges[id].to-100]=i;
                    break;
                }
            }
        }
        rep(i,1,n)
            cout<<ans[i]<<(i==n?'
    ':' ');
    }
    int main()
    {
        closeSync;
        //multiCase
        {
            solve();
        }
        return 0;
    }
    

  • 相关阅读:
    C++ 虚函数表解析
    函数调用运算符重载
    成员访问运算符重载
    递增和递减运算符重载
    java 如何查看jdk版本&位数
    oracle 11g完美卸载
    win10 你没有足够的权限执行此操作。
    maven 找不到或无法加载主类
    eclipse 如何对maven项目进行打包?
    Core Dataeasy出现的错误
  • 原文地址:https://www.cnblogs.com/stelayuri/p/14308914.html
Copyright © 2020-2023  润新知