题解 [CQOI2015] 网络吞吐量

Description

现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),网络中的路由器使用 1 到 n 编号,假设所有数据包一定沿最短路径转发,试计算从路由器 1 到路由器 n 的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1 到路由器 n 作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1 和 n 直接相连的链路。

本来以为是道水题,没想到是坑。

刚开始以为可以直接在原图上跑费用流。

但是有点权和最短路的限制,显然我们要重新建图。

在建图前跑SPFA求最短路(数据应该卡不掉,只要你常数小)。

由于只能在最短路上流,我们可以枚举每条边看是否在最短路上。

如果在就连边。

**注意:**这题的数据有重边,如果用邻接矩阵,要特判取min!!!!

如果你用vector就没事。

(这就是我爆零原因/kk)。

而对于c的限制,我们可以拆点,从i向i‘连一条ci的边。

但是1和n要连无限大。

最后就可以跑最大流惹qwq。

另:此题不用建源汇点,直接用1和n就行 虽然我还是建了

很重要:

1.不开longlong见祖宗!

2.INF赋小见上帝!

3.不判重两行泪!

出题人好毒QAQ

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+9,INF=5e17;

int dis[N],ver[N<<1],w[N<<1],nxt[N<<1],h[N],cur[N],dep[N];
int n,m,c[N],x,y,z,ans,g[509][509],tot=1,s=0,t=1501;
bool vis[N];

inline void SPFA()
{
	queue<int> Q;
	for(int i=2;i<=n;i++) dis[i]=INF;
	Q.push(1),vis[1]=true;dis[1]=0;
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		vis[u]=0;
		for(int i=0;i<=n;i++)
		{
			if(dis[i]>dis[u]+g[u][i]&&g[u][i]!=-1)
			{
				dis[i]=dis[u]+g[u][i];
				if(!vis[i]) Q.push(i),vis[i]=true;
			}
		}
	}
}

inline void addedge(int x,int y,int z)
{
	ver[++tot]=y,w[tot]=z,nxt[tot]=h[x],h[x]=tot;
	ver[++tot]=x,w[tot]=0,nxt[tot]=h[y],h[y]=tot;
}

inline bool bfs()
{
	queue<int> Q;
	memset(dep,-1,sizeof dep);
	Q.push(s);dep[s]=0;
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		for(int i=h[u];i;i=nxt[i])
		{
			int v=ver[i];
			if(dep[v]==-1&&w[i]>0)
			{
				Q.push(v);
				dep[v]=dep[u]+1;
			}
		}
	}
	return dep[t]!=-1;
}

inline int dfs(int u,int flow)
{
	if(u==t) return flow;
	int delta,max_flow=0;
	for(int i=cur[u];i;i=nxt[i])
	{
		cur[u]=i;
		int v=ver[i];
		if(dep[v]==dep[u]+1&&w[i]>0)
		{
			delta=dfs(v,min(w[i],flow));
			flow-=delta;
			max_flow+=delta;
			w[i]-=delta;
			w[i^1]+=delta;
			if(!flow) break;
		}
	}
	return max_flow;
}

inline void Dinic()
{
	while(bfs())
	{
		memcpy(cur,h,sizeof h);
		ans+=dfs(s,INF);
	}
}

signed main()
{
    // freopen("Alansp.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	t=n*2+1;
     memset(g,-1,sizeof g);
    for(int i=1;i<=m;i++) 
    {
        scanf("%lld%lld%lld",&x,&y,&z);
        if(g[x][y]==-1) g[x][y]=g[y][x]=z;
        else g[x][y]=min(g[x][y],z),g[y][x]=g[x][y];
    }
	// for(int i=1;i<=n;i++)
    // {
    //     for(int j=1;j<=n;j++) if(g[i][j]!=-1) cout<<i<<' '<<j<<endl;
    // }
    for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
	SPFA();
    // for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
	addedge(s,1,INF),addedge(n*2,t,INF);
	for(int i=1;i<=n;i++) 
	{
		if(i!=1&&i!=n) addedge(i,i+n,c[i]);
		else addedge(i,i+n,INF);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{ 
			if(i==j) continue;
			if(dis[i]+g[i][j]==dis[j]&&g[i][j]!=-1) addedge(i+n,j,INF);
		}
	}
	Dinic();
	printf("%lld",ans);
	return 0;
}