[2019HDU多校第一场][HDU 6582][E. Path]

 题意: t 组样例,n个点,m条边。i 行a到b距离c. 要求去掉最短路的最小代价。去掉每条路代价等于长度。

解:spfa跑出最短路,找出最短路建图,对新图求最小割

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf = 1e17+7;
const ll M = 100005;
const ll N = 100005;
struct E{
    ll nxt,v,w;
};
E edge[M];
ll dpth[M],head[M];
ll n,m;
ll dis1[M],dis2[M];
ll cnt;
ll vis[M];
void add(ll u,ll v,ll w){
    cnt++;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}
void spfa(ll s,ll dd[]){
    memset(vis,0,sizeof(vis));
    for(ll i=0;i<=n;i++)dd[i] = inf;
    queue<ll> q;
    dd[s] = 0; vis[s] = 1; q.push(s);
    while(!q.empty()){
        ll u = q.front(); q.pop(); vis[u] = 0;
        for(ll v,w,i=head[u];i!=-1;i=edge[i].nxt){
            v = edge[i].v; w = dd[u]+edge[i].w;
            if(dd[v]>w){
                dd[v] = w;
                if(!vis[v]) vis[v]=1,q.push(v);
            }
        }
        
    }
}

//初始化从0开始存边 i^1是i的反向边
void init(){
    cnt=-1;
    for(int i=0;i<=n+1;i++)
    	head[i]=-1;
}
struct Edge
{
    ll from,to,cap,flow;
    Edge(ll u,ll v,ll c,ll f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic
{
    ll s,t;
    vector<Edge>edges;        
    vector<ll> G[10005];      
    bool vis[N];           
    ll d[N];             
    ll cur[N];            
    void init()
    {
       for (ll i=0;i<=n+1;i++)
           G[i].clear(),cur[i]=0,d[i]=0,vis[i]=0;
       edges.clear();
    }
    void AddEdge(ll from,ll to,ll cap)
    {
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));       
        ll mm=edges.size();
        G[from].push_back(mm-2);
        G[to].push_back(mm-1);
    }
    bool BFS()
    {
        memset(vis,0,sizeof(vis));
        queue<ll>q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while (!q.empty())
        {
            ll x = q.front();q.pop();
            for (ll i = 0;i<G[x].size();i++)
            {
                Edge &e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to]=1;
                    d[e.to] = d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    ll DFS(ll x,ll a)
    {
        if (x==t || a==0)
            return a;
        ll flow = 0,f;
        for(ll &i=cur[x];i<G[x].size();i++)
        {
            Edge &e = edges[G[x][i]];
            if (d[x]+1 == d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if (a==0)
                    break;
            }
        }
        return flow;
    }
    ll Maxflow(ll s,ll t)
    {
        this->s=s;
        this->t=t;
        ll flow = 0;
        while (BFS())
        {
            memset(cur,0,sizeof(cur));
            flow+=DFS(s,inf);
        }
        return flow;
    }
}dc;

ll a[M],b[M],c[M];
int main(){
    ll T,x,y,z;
    scanf("%lld",&T);
    while(T--){
        scanf("%lld %lld",&n,&m);
        init();
        for(ll i=1;i<=m;i++){
            scanf("%lld %lld %lld",&x,&y,&z);
            a[i] = x;    b[i] = y;    c[i] = z;
            add(x,y,z);
        } 
        dc.s = 1; dc.t = n;
        spfa(1,dis1);    
        
        cnt = -1;
        for(ll i=0;i<=n+1;i++)head[i] = -1;
        
        for(ll i=1;i<=m;i++){
            x = a[i];    y = b[i];    z = c[i];
            add(y,x,z);    
        }
        
        spfa(n,dis2);
        
		dc.init();
        
        for(ll i=1;i<=m;i++){
            if(a[i]!=b[i]&&dis1[a[i]]+c[i]+dis2[b[i]]==dis1[n]){
                dc.AddEdge(a[i],b[i],c[i]);  
            }
        }
        cout<<dc.Maxflow(1,n)<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值