BZOJ 3876 [Ahoi2014&Jsoi2014]支线剧情

题解:

带下界的费用流

对于x->y边权为z Addedge(x,t,1,0) Addedge(s,y,1,z) Addedge(x,y,inf,0)

然后对每个点Addedge(i,1,inf,0)

然后跑最小费用最大流即可

因为这是DAG,所以每一个循环流都是从1到某个点再到1的路径

也就是说用几个费用最小的循环流来满足下界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=3000;
const int oo=1000000000;
 
int n;
struct Edge{
    int from,to,cap,flow,cost;
};
vector<int>G[maxn];
vector<Edge>edges;
void Addedge(int x,int y,int z,int w){
    Edge e;
    e.from=x;e.to=y;e.cap=z;e.flow=0;e.cost=w;
    edges.push_back(e);
    e.from=y;e.to=x;e.cap=0;e.flow=0;e.cost=-w;
    edges.push_back(e);
    int c=edges.size();
    G[x].push_back(c-2);
    G[y].push_back(c-1);
}
 
int s,t,totn;
int inq[maxn];
int d[maxn];
int pre[maxn];
queue<int>q;
int Spfa(int &nowflow,int &nowcost){
    for(int i=1;i<=totn;++i){
        inq[i]=0;d[i]=oo;
    }
    d[s]=0;inq[s]=1;q.push(s);
    while(!q.empty()){
        int x=q.front();q.pop();inq[x]=0;
        for(int i=0;i<G[x].size();++i){
            Edge e=edges[G[x][i]];
            if((e.cap>e.flow)&&(d[x]+e.cost<d[e.to])){
                d[e.to]=d[x]+e.cost;
                pre[e.to]=G[x][i];
                if(!inq[e.to]){
                    inq[e.to]=1;
                    q.push(e.to);
                }
            }
        }
    }
    if(d[t]==oo)return 0;
     
    int x=t,f=oo;
    while(x!=s){
        Edge e=edges[pre[x]];
        f=min(f,e.cap-e.flow);
        x=e.from;
    }
    nowflow+=f;nowcost+=f*d[t];
    x=t;
    while(x!=s){
        edges[pre[x]].flow+=f;
        edges[pre[x]^1].flow-=f;
        x=edges[pre[x]].from;
    }
    return 1;
}
 
int Mincost(){
    int flow=0,cost=0;
    while(Spfa(flow,cost)){
    }
    return cost;
}
 
int main(){
    scanf("%d",&n);
    s=n+1;t=n+2;totn=t;
    for(int i=1;i<=n;++i){
        int m;scanf("%d",&m);
        Addedge(i,t,m,0);
        while(m--){
            int y,z;
            scanf("%d%d",&y,&z);
//          Addedge(i,y,oo,z);
            Addedge(s,y,1,z);
        }
    }
    for(int i=2;i<=n;++i)Addedge(i,1,oo,0);
     
    printf("%d\n",Mincost());
    return 0;
}

 

  

 

posted @   ws_zzy  阅读(125)  评论(0编辑  收藏  举报
编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
· 重磅发布!DeepSeek 微调秘籍揭秘,一键解锁升级版全家桶,AI 玩家必备神器!
点击右上角即可分享
微信分享提示