[CQOI2015]网络吞吐量(最短路+最大流)

题目链接

 

 思路:跑一遍最短路求出起点到每个点的最短距离,然后就可以去掉无关的边了,最后跑一遍最大流即可。

每个路由器的容量,点化为边,转化为边的最大流即可

有个坑点是输入会有重边,无语了

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pb push_back
#define IOS ios::sync_with_stdio(false)
#define int long long
#define inf 1e18
typedef long long ll;
const int N=1e3+10;
const int M=2e5+10;
const int p = 100000;
int s,t,n,m;
int d[N];
int a[N];

int ans1;
int g[N][N];
struct ty
{
    int u,t,next,flow;
    bool operator < (const ty&p) const
    {
        return flow > p.flow;
    }
}edge[M];
int tot=1,head[N];
void add(int x ,int y, int flow)
{
    edge[++tot]={x,y,head[x],flow};
    head[x]=tot;
}
void ini()
{
    tot=1;
    mst(head,-1);
}
bool bfs(int t)
{
    mst(d,0);
    queue <int> q;
    q.push(s);
    d[s]=1;
    while( !q.empty() )
    {
        int x = q.front();
        q.pop();
        if( x==t ) return true;
        for(int i=head[x] ;i!=-1;i=edge[i].next)
        {
            int y = edge[i].t;
            if( edge[i].flow > 0 && !d[y] )
            {
                d[y] = d[x] + 1;
                q.push(y);
            }
        }
    }
    return false;
}
int dfs(int x ,int flow ,int t)
{
    if( x==t ) return flow;
    int sum=0;
    for(int i=head[x] ;i!=-1;i=edge[i].next)
    {
        int y = edge[i].t;
        if( d[y] == d[x] +1 && edge[i].flow>0 )
        {
            int temp = dfs(y,min(edge[i].flow , flow-sum),t);
            edge[i].flow -= temp;
            edge[i^1].flow += temp;
            sum += temp;
            if( sum == flow ) return flow;
        }
    }
    return sum;
}
int dis[N];
bool v[N];
void dij(int s ,int t)
{
    mst(dis,0x3f);
    priority_queue <ty> q;
    q.push({0,s,0,0});
    dis[s]=0;
    while( !q.empty() )
    {
        ty x = q.top();
        q.pop();
        if( v[x.t] ) continue;
        v[x.t]=1;
        for(int i=head[x.t] ;i!=-1 ;i=edge[i].next)
        {
            int y = edge[i].t;
            int len = edge[i].flow;
            if( dis[y] > dis[x.t] + len )
            {
                dis[y] = dis[x.t] + len;
                q.push({0,y,0,dis[y]});
            }
        }

    }
}
signed main()
{
    ///!!!
//    freopen("data.txt","r",stdin);
    //!!!=
    IOS;
    ini();
    cin>>n>>m;
    _for(i,1,m)
    {
        int x,y,z;cin>>x>>y>>z;
        add(x,y,z);
        add(y,x,z);
        //nmd还会有重边,无语了
        if( !g[x][y]) g[x][y] = g[y][x]= z;
        else g[x][y] = g[y][x]= min(g[x][y],z);
    }
    dij(1,n);
    ini();
    _for(i,1,n)
    {
        int w;cin>>w;
        if( i==1 || i==n ) w=inf;//起点终点无限流量
        add(i,i+n,w);//化点为边
        add(i+n,i,0);
        _for(j,i+1,n)
        {
            if( dis[i] + g[i][j] == dis[j] && g[i][j] )//是最短路
            {
                add(i+n,j,inf),add(j,i+n,0);
            }
            if( dis[j] + g[i][j] == dis[i] && g[i][j] )//是最短路
            {
                add(j+n,i,inf),add(i,j+n,0);
            }
        }
    }
    int ans=0;
    s=1,t=2*n;//起点终点
    while( bfs(t) ) ans += dfs(s,inf,t);
    cout<<ans<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值