Path HDU - 6582【求最短路所有边+最小割】

题意:

  给一个有向图,删除每一条边的代价是边的长度,要求花费最小的代价,使得 1 n 1\to n 最短路变长,求该最小花费。

思路:

  要使得最短路变长,那么删除的边一定要破坏原来的最短路。即要先把所有最短路的所有边找出来,通过删除某几条边,使得所有的最短路无效。
  如何把最短路的所有边全部找出呢?以 d i s 1 [ i ] dis1[i] 表示原图中, 1 1 号节点到其余节点的最短距离;以 d i s 2 [ i ] dis2[i] 表示反向建图后 n n 号节点到各节点的最小距离。如果一条边是最短路径上的边,假设两端点为 u u v v ,边权为 w w ,则有:
d i s 1 [ u ] + w + d i s 2 [ v ] = d i s 1 [ n ] dis1[u]+w+dis2[v]=dis1[n]
所以在正向和反向建图跑两遍最短路后,遍历所有边就可以求出。
接下来在有这些边建成的图上删除边,使得 1 1 n n 号点不连通。显然就是求最小割。
理论上 D i n i c Dinic 的时间复杂度是 O ( n 2 m ) O(n^2*m) ,但实际上要优的多。
AC代码:

#include <bits/stdc++.h>//把所有最短路的所有边找出,然后跑最大流
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
const int N=1e4+5;
const ll inf=1e16;//注意取值范围设置合理的inf,WA的好惨
struct edge
{
    int from;
    int too;
    ll val;
};
struct node
{
    int to;
    ll val;
    int rev;
};
vector<P>pic[2][N];//正向和反向边
vector<edge>eg;//存边
vector<node>pa[N];//网络流的图
priority_queue<P,vector<P>,greater<P> >que;
queue<int>q;
ll dis[2][N];
int layer[N],iter[N];
int n;
void init()
{
    for(int j=0;j<2;j++)
    {
        for(int i=0;i<=n;i++)
            pic[j][i].clear();
        for(int i=0;i<=n;i++)
            dis[j][i]=inf;
    }
    eg.clear();
    for(int i=0;i<=n;i++)
        pa[i].clear();
}
void dij(int s)
{
    while(!que.empty())
        que.pop();
    if(s==0)
    {
        que.push(make_pair(0,1));
        dis[s][1]=0;
    }
    else
    {
        que.push(make_pair(0,n));
        dis[s][n]=0;
    }
    while(!que.empty())
    {
        P now=que.top();
        que.pop();
        if(now.first>dis[s][now.second])
            continue;
        for(int i=0;i<pic[s][now.second].size();i++)
        {
            P tmp=pic[s][now.second][i];
            if(tmp.first+dis[s][now.second]<dis[s][tmp.second])
            {
                dis[s][tmp.second]=tmp.first+dis[s][now.second];
                que.push(make_pair(dis[s][tmp.second],tmp.second));
            }
        }
    }
}
void addedge(int u,int v,ll w)
{
    pa[u].push_back(node{v,w,pa[v].size()});
    pa[v].push_back(node{u,0,pa[u].size()-1});
}
bool bfs()
{
    while(!q.empty())
        q.pop();
    fill(layer,layer+n+1,-1);
    layer[1]=0;
    q.push(1);
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<pa[now].size();i++)
        {
            node t=pa[now][i];
            if(layer[t.to]<0&&t.val>0)
            {
                layer[t.to]=layer[now]+1;
                q.push(t.to);
                if(t.to==n)
                    return true;
            }
        }
    }
    return false;
}
ll dfs(int v,ll w)
{
    if(v==n)
        return w;
    for(int &i=iter[v];i<pa[v].size();i++)
    {
        node &e=pa[v][i];//cout<<"val="<<e.val<<endl;
        if(e.val>0&&layer[e.to]>layer[v])
        {
            ll d=dfs(e.to,min(w,e.val));
            if(d>0)
            {
                e.val-=d;
                pa[e.to][e.rev].val+=d;
                return d;
            }
        }
    }
    return 0;
}
ll dinic()
{
  ll maxflow=0;
  while(bfs())
  {
      ll f=0;
      fill(iter,iter+1+n,0);
      while((f=dfs(1,inf))>0)
        maxflow+=f;//,cout<<"f="<<f<<endl;
  }
  return maxflow;
}
int main()
{
    int t,m;
    scanf("%d",&t);
    while(t--)
    {
        int u,v;
        ll w;
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld",&u,&v,&w);
            pic[0][u].push_back(make_pair(w,v));
            pic[1][v].push_back(make_pair(w,u));
            eg.push_back(edge{u,v,w});
        }
        dij(0);
        dij(1);
        for(int i=0;i<eg.size();i++)
        {
            if(dis[0][eg[i].from]+dis[1][eg[i].too]+eg[i].val==dis[0][n])
                addedge(eg[i].from,eg[i].too,eg[i].val);
        }
        printf("%lld\n",dinic());
    }
    return 0;
}

发布了121 篇原创文章 · 获赞 11 · 访问量 2107

猜你喜欢

转载自blog.csdn.net/weixin_43184669/article/details/104417420