zoukankan      html  css  js  c++  java
  • magic

    magic

    题目描述

     

    给定一个n个点,m条边的有向图。

    对于任意一个点i,都有两个权值ai,bi。你可以花费bi的费用将这个点的ai变成0。

    另外对于圈中的每个点你需要付出wi=Max(i,j)∈E aj

     

     

    请最小化所有费用之和。

     

     

    输入

     

    第一行两个数n,m。

    接下来一行n个数,表示ai。

    接下来一行n个数,表示bi。

    接下来m行,每行2个数i,j , 表示一行(i,j)的边

     

     

    输出

     

    输出一个数,表示最小化的费用

     

     

    样例输入

    2 1
    100000 10000
    100000 1
    1 2

    样例输出

    1

    提示

     

    【样例说明】最优的方案是花费1的费用将a2变成0

    【数据范围】
    对于30%的数据,n<=20
    对于100%的数据,n<=1000,m<=50000

     

    solution

    一个神奇的建图方法

    对于原图中的每一个点,建out[i]个点(out[i]表示i的出度)

    这out[i]个点和T连边,流量b[i]

    把这out[i]个点按a[i]排序

    差分(保证代价正确)

    然后再把这out个点连inf的边(一起选)

     

    如图

     

    嗯有点丑

    意会一下

    然后最小割即可

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define maxn 200005
    #define inf 1e9
    using namespace std;
    int n,m,a1[1002],b1[1002],u1[50002],v1[50002],tot=1;
    int head[maxn],cnt,S,T,d[maxn],flag[maxn],top,ans,cur[maxn];
    vector<int>G[maxn];
    queue<int>q;
    struct node{
        int id,v;
    }t[maxn];
    struct no{
        int v,nex,cap;
    }e[400005];
    bool cmp(node aa,node bb){
        return aa.v<bb.v;
    }
    void add(int t1,int t2,int t3){
        e[++tot].v=t2;e[tot].cap=t3;e[tot].nex=head[t1];head[t1]=tot;
    }
    void lj(int t1,int t2,int t3){
        add(t1,t2,t3);add(t2,t1,0);
    }
    bool BFS(){
         
        for(int i=1;i<=T;i++)d[i]=inf;
        d[S]=0;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();
            cur[x]=head[x];
            for(int i=head[x];i;i=e[i].nex){
                //cout<<e[i].v<<' '<<x<<endl;
                if(d[e[i].v]>d[x]+1&&e[i].cap>0){
                    d[e[i].v]=d[x]+1;
                    if(!flag[e[i].v]){
                        flag[e[i].v]=1;q.push(e[i].v);
                    }
                }
            }
            flag[x]=0;
        }
        return d[T]!=inf;
    }
    int lian(int k,int a){
        if(k==T||!a)return a;
        int f,flow=0;
        for(int &i=cur[k];i;i=e[i].nex){
            if(d[e[i].v]==d[k]+1&&(f=lian(e[i].v,min(e[i].cap,a)))>0){
                e[i].cap-=f;e[i^1].cap+=f;
                a-=f;flow+=f;
                if(!a)break;
            }
        }
        return flow;
    }
    int main()
    {
        cin>>n>>m;
        S=200002,T=S+1;cnt=n;
        for(int i=1;i<=n;i++)scanf("%d",&a1[i]);
        for(int i=1;i<=n;i++){
            scanf("%d",&b1[i]);
            lj(i,T,b1[i]);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u1[i],&v1[i]);
            G[u1[i]].push_back(v1[i]);
        }
        for(int i=1;i<=n;i++){
            int sz=G[i].size();
            for(int j=0;j<sz;j++){
                t[j].id=G[i][j],t[j].v=a1[G[i][j]];
            }
            sort(t,t+sz,cmp);
            for(int i=0;i<sz;i++){
                int now=++cnt;
                if(i==0)lj(S,now,t[i].v);
                else {
                    lj(S,now,t[i].v-t[i-1].v);
                    lj(now-1,now,inf);
                }
                lj(now,t[i].id,inf);
            }
        }
        while(BFS())ans+=lian(S,inf);
        cout<<ans<<endl;
        return 0;
    }
     
  • 相关阅读:
    GitBook基本使用
    Window 远程桌面漏洞风险,各个厂家的扫描修复方案(CVE-2019-0708)
    应急响应实战笔记(续)
    不同系统下,复制文件时新文件的日期区别
    Window应急响应(六):NesMiner挖矿病毒
    利用python输出000至999中间的数
    揭秘骗局:这是一张会变的图片
    如何查看github排行热度
    zabbix使用自动发现功能批量监控服务器端口的可用性
    使用python脚本批量设置nginx站点的rewrite规则
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358872.html
Copyright © 2011-2022 走看看