magic

题目

题目描述

给定一个$n$个点,$m$条边的有向图
对于任意一个点$i$,都有两个权值$a_i,b_i$
你可以花费$b_i$的费用将这个点的$a_i$变成$0$
另外对于圈中的每个点你需要付出$wi=Max(i,j)\in E~aj$
请最小化所有费用之和

输入格式

第一行两个数$n$,$m$
接下来一行$n$个数,表示$a_i$
接下来一行$n$个数,表示$b_i$
接下来$m$行,每行$2$个数$i,j$,表示一行$(i,j)$的边

输出格式

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

样例

样例输入

2 1
100000 10000
100000 1
1 2

样例输出

1

数据范围与提示

样例说明

最优的方案是花费$1$的费用将$a_2$变成$0$

数据范围

对于$30%$的数据,$n\leqslant 20$
对于$100%$的数据,$n\leqslant 1000,m\leqslant 50000$

题解

奇奇怪怪的建图、跑网络流方法……
对于原图中的每一个点,建$i$的出度个点,把这些点和终点连上流量为$b_i$的边,然后把这些个点按$a_i$的值从小到大排序
然后搞个差分,再在这些个点之间连上流量为inf的边
最后跑一个网络流就可以啦!
注意,DFS中的取地址符非常重要,去掉了之后会超时,虽然我也不知道为啥反正就是加了就过了,因为我平常些Dinic的时候也不加这个取地址符
附上代码:

#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
struct ppap1
{
    int v,h;
}temp[200010];
struct ppap2
{
    int to,nxt,ver;
}e[400010];
vector<int> t[200010];
queue<int> q;
int n,m,S,T,tot=1,len,ans,a[1010],b[1010],u[50010],v[50010],head[200010],Head[200010],d[200010],vis[200010];
inline int read()
{
    int X=0; bool flag=1; char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
    if(flag) return X;
    return ~(X-1);
}
inline bool cmp(ppap1 a,ppap1 b)
{
    return a.v<b.v;
}
inline void add(int u,int v,int w)
{
    e[++tot].nxt=head[u],head[u]=tot,e[tot].to=v,e[tot].ver=w;
    e[++tot].nxt=head[v],head[v]=tot,e[tot].to=u,e[tot].ver=0;
}
inline bool bfs()
{
    for(int i=1;i<=T;i++) d[i]=1e9;
    d[S]=0,q.push(S);
    while(!q.empty()){
        int x=q.front();
        q.pop(),Head[x]=head[x];
        for(int i=head[x];i;i=e[i].nxt) if(d[e[i].to]>d[x]+1&&e[i].ver>0){
            d[e[i].to]=d[x]+1;
            if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
        }
        vis[x]=0;
    }
    return d[T]!=1e9;
}
inline int dfs(int x,int Flow)
{
    if(x==T||(!Flow)) return Flow;
    int k,flow=0;
    for(int &i=Head[x];i;i=e[i].nxt) if(d[e[i].to]==d[x]+1&&(k=dfs(e[i].to,min(e[i].ver,Flow)))>0){
        e[i].ver-=k,e[i^1].ver+=k,Flow-=k,flow+=k;
        if(!Flow) break;
    }
    return flow;
}
int main()
{
    n=read(),m=read();
    S=200002,T=S+1,len=n;
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) b[i]=read(),add(i,T,b[i]);
    for(int i=1;i<=m;i++) u[i]=read(),v[i]=read(),t[u[i]].push_back(v[i]);
    for(int i=1,size;i<=n;i++){
        size=t[i].size();
        for(int j=0;j<size;j++) temp[j].h=t[i][j],temp[j].v=a[t[i][j]];
        sort(temp,temp+size,cmp);
        for(int j=0,tem;j<size;j++){
            tem=++len;
            if(!j) add(S,tem,temp[j].v);
            else add(S,tem,temp[j].v-temp[j-1].v),add(tem-1,tem,1e9);
            add(tem,temp[j].h,1e9);
        }
    }
    while(bfs()) ans+=dfs(S,1e9);
    printf("%d",ans);
}

喜欢的话,给博主赏一杯冰阔乐吧~


  转载请注明: Maserhe magic

 上一篇
最短Hamilton路径 最短Hamilton路径
题目:最短Hamilton路径题目描述给定一张 $n$个点的带权无向图,点从 $0$ ~ $n$-1 标号,求起点 0 到终点 $n$-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰
下一篇 
Christmas Christmas
题目题目描述 给出一个长度为$n$的整数序列。你的程序需要依次完成如下操作: $Aab~c$:将区间$[a,b]$中的每个数加上$c$ $Mab~c$: 对区间$[a,b]$中的每个数$x$,令$x=max(x,c)$ $Q~a$:求序列
2020-03-11
  目录