bzoj1927: [Sdoi2010]星际竞速 最小费用流

和软件安装比较相似的拆点模型.   

我们发现,每个点只能经过一次,也就是说每个点最多可以贡献给其他点一次.   

然后连边方式和软件安装就几乎是相同的了.  

code: 

#include <bits/stdc++.h>  
#define N 2008   
#define inf 10000000 
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int s,t,n,m,flow,ans;      
namespace mcmf      
{     
    int d[N],a[N],flow2[N],inq[N];      
    struct Edge
    {
        int u,v,cap,cost;  
        Edge(int u=0,int v=0,int cap=0,int cost=0):u(u),v(v),cap(cap),cost(cost){}  
    };  
    queue<int>q;     
    vector<int>G[N];
    vector<Edge>edges;      
    inline void add(int u,int v,int cap,int cost) 
    {   
        edges.push_back(Edge(u,v,cap,cost));   
        edges.push_back(Edge(v,u,0,-cost));   
        int p=edges.size();   
        G[u].push_back(p-2);  
        G[v].push_back(p-1);  
    }
    int spfa() 
    {
        for(int i=0;i<N;++i) d[i]=flow2[i]=inf;  
        memset(inq,0,sizeof(inq));   
        d[s]=0,inq[s]=1,q.push(s);  
        while(!q.empty()) 
        {
            int u=q.front(); q.pop(),inq[u]=0;      
            for(int i=0;i<G[u].size();++i) 
            {
                Edge e=edges[G[u][i]];    
                if(e.cap>0&&d[e.v]>d[u]+e.cost) 
                {
                    d[e.v]=d[u]+e.cost;   
                    flow2[e.v]=min(flow2[u],e.cap);    
                    a[e.v]=G[u][i];   
                    if(!inq[e.v]) 
                    {
                        inq[e.v]=1;   
                        q.push(e.v);   
                    }
                }
            }
        }  
        if(d[t]==inf) return 0;       
        int f=flow2[t];   
        flow+=f;  
        int u=edges[a[t]].u;   
        edges[a[t]].cap-=f;  
        edges[a[t]^1].cap+=f;   
        while(u!=s) 
        {
            edges[a[u]].cap-=f;   
            edges[a[u]^1].cap+=f;   
            u=edges[a[u]].u;      
        }        
        ans+=d[t]*f;   
        return 1;     
    }
    inline int maxflow() { while(spfa()); return flow; }   
    inline int getcost() { return ans; }   
};  
int tim[N];  
int I1(int x) { return x; }   
int I2(int x) { return x+n; }    
int main() 
{ 
    // setIO("input");     
    scanf("%d%d",&n,&m);   
    for(int i=1;i<=n;++i) scanf("%d",&tim[i]);       
    s=0,t=(n<<1)+1;        
    for(int i=1;i<=n;++i) 
    {
        mcmf::add(s,I1(i),1,0);   
        mcmf::add(I2(i),t,1,0);        
        mcmf::add(s,I2(i),1,tim[i]);             
                             
    }
    for(int i=1;i<=m;++i) 
    {
        int u,v,w;  
        scanf("%d%d%d",&u,&v,&w);   
        if(u>v) swap(u,v);  
        mcmf::add(I1(u),I2(v),1,w);    
    }
    mcmf::maxflow();  
    printf("%d\n",mcmf::getcost());  
    return 0;  
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值