zoukankan      html  css  js  c++  java
  • UESCT 1220 题解

    题意:有M个战役,N个村庄,每当曹操从第i个村庄抽调k个人去往xi战场,第i个村庄会抽调k个人投奔袁绍去往yi战场,且曹操需要为抽调行为支付k*ci的钱,战役分为三种:

    1. 极其重要:要求曹操方战场上士兵多于袁绍方
    2. 重要:要求曹操方战场上士兵不少于袁绍方
    3. 不重要:无所谓

    求曹操为了获胜(所有战役满足以上条件)需要支付的金额最小值,若曹操无法获胜,则输出-1

    1<=N<=100000;1<=M<=100000;0<=ci<=100000;

    1~30组数据,3000MS

    题解:特殊最小费用最大流。

    构图是关键,从super源向所有的不重要的点连容量为inf,单位费用为0的边,从所有极其重要的点向super汇连容量为1,单位费用为0的边,而从yi点向xi点连容量为inf,单位费用为ci的边(每个战场上只考虑净人数:曹操方人数-袁绍方人数,则从第i个村庄抽调人手相当于从yi战场上向xi战场上抽调人手)。

    但想来直接跑费用流会TLE(O(M(N+M)log(N+M))),注意到这个图中,且每次增广流量最大为1,且中间的边容量全为inf,所以可以直接从源开始做一次单源最短路,ans即源点到所有极其重要点距离之和(有无法到达的点则ans=-1),复杂度O((N+M)log(N+M))

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    const long long inf=20000000000;
    long long ans;
    const int maxn=200000;
    int t,n,m,x[maxn],y[maxn],c[maxn],w[maxn];
    vector <pair<int,int>> edge[maxn];
    long long dis[maxn];
    queue<int> dl;
    bool v[maxn];
    
    void spfa(){
        int now,to,fy;
        memset(v,false,sizeof(v));
        while (!dl.empty()) dl.pop();
        for (int i=1;i<=m;++i) dis[i]=inf;dis[0]=0;
        dl.push(0);v[0]=true;
        while (!dl.empty()){
            now=dl.front();dl.pop();
            v[now]=false;
            for (int i=0;i<edge[now].size();++i){
                to=edge[now][i].first;fy=edge[now][i].second;
                if (dis[to]>fy+dis[now]){
                    dis[to]=fy+dis[now];
                    if (!v[to]) {dl.push(to);v[to]=true;} 
                }
            }
        }
    }
    
    int main(){
        scanf("%d",&t);
        for (int q=1;q<=t;++q){
            scanf("%d%d",&n,&m);
            for (int i=0;i<=n;++i) edge[i].clear();
            for (int i=1;i<=n;++i) scanf("%d",&x[i]);
            for (int i=1;i<=n;++i) scanf("%d",&y[i]);
            for (int i=1;i<=n;++i) scanf("%d",&w[i]);
            for (int i=1;i<=n;++i) edge[y[i]].push_back(make_pair(x[i],w[i]));
            for (int i=1;i<=m;++i) {scanf("%d",&w[i]);if (w[i]==0) edge[0].push_back(make_pair(i,0));}
            spfa(); 
            ans=0;
            for (int i=1;i<=m;++i) if (w[i]==2) {
                if (dis[i]==inf) {ans=-1;break;} else ans+=dis[i];
            }
            printf("Case #%d: %lld
    ",q,ans);
        }
        return 0;
    }
  • 相关阅读:
    2.1 CDN Bypass
    4.1 SQL Injection
    ztosec/secscan-authcheck 安装部署教程
    浏览器的内部构造
    左右值的概念
    网络安全学习路线
    Python+Typora博客图片上传
    微信欢乐五子棋辅助
    [SUCTF 2019]EasySQL
    [护网杯 2018]easy_tornado (SSTI)
  • 原文地址:https://www.cnblogs.com/terra/p/6992605.html
Copyright © 2011-2022 走看看