洛谷 P3171 [CQOI2015]网络吞吐量 题解【网络流】【最短路计数】
点击量:128
我自己AC的做法居然是错的。。。
题目描述
路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点。网络中实现路由转发的硬件设备称为路由器。为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包。例如在常用的路由算法OSPF(开放式最短路径优先)中,路由器会使用经典的Dijkstra算法计算最短路径,然后尽量沿最短路径转发数据包。现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),假设所有数据包一定沿最短路径转发,试计算从路由器1到路由器n的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1到路由器n作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1和n直接相连的链路。
输入输出格式
输入格式:
输入文件第一行包含两个空格分开的正整数n和m,分别表示路由器数量和链路的数量。网络中的路由器使用1到n编号。接下来m行,每行包含三个空格分开的正整数a、b和d,表示从路由器a到路由器b存在一条距离为d的双向链路。 接下来n行,每行包含一个正整数c,分别给出每一个路由器的吞吐量。
输出格式:
输出一个整数,为题目所求吞吐量。
输入输出样例
输入样例#1:7 101 2 21 5 22 4 12 3 33 7 14 5 44 3 14 6 15 6 26 7 11100205020601输出样例#1:70说明
对于100%的数据,n<=500,m<=100000,d,c<=10^9
首先,这个题一定要开long long,不然会和没写一样。。。
非完美解法:
看到这个题,用网络流来限流当然是第一想法。于是先spfa求最短路,接着枚举每个点是否在最短路上。判断方法:从起点/终点出发各跑一遍最短路,记录dis[0]和dis[1],最后枚举每条边是否满足$ dis[0][u]+w+dis[1][v]=dis[0][t]$(t表示终点)。如果在,就把它加入网络流图中,流量为两端点中吞吐量较小的一个。这种做法看上去没有问题,因为两个点相连新吞吐量依赖于较低的点的吞吐量。
不过一个点不一定只有这一条流连接,当有多条流流入且有多条流流出时,它的流量可以被扩充超过它的吞吐量。比如说十字路口这种图:
所有点的吞吐量均为1。
即使4号点的吞吐量为1,也只能构建出这样的图,而这时最大流为2,不符合题意。当这个十字路口变为度为2k的点时,它的流量可以达到吞吐量×k。
可能是数据不够强,致使我这种非完美解法能通过。
正确解法:
把一个点拆成两个,一个管进入,一个管流出,两个点之间以吞吐量为流量的边连接起来。再把最短路上满足条件的点(分拆点的进出)相连,权值为inf。直接跑1到n的最大流,最大流就是答案了。
非完美Code:
#include<cstdio>
#include<cstring>
#include<queue>
using std::deque;
int min(int x,int y)
{
return x<y?x:y;
}
namespace graph//建了两个图所以用命名空间
{
struct edge
{
int n;
int v;
int nxt;
edge(int n,int v,int nxt)
{
this->n=n;
this->v=v;
this->nxt=nxt;
}
edge()
{
nxt=-1;
}
}e[210000];
int head[501],cnt=-1;
void add(int from,int to,int v)
{
e[++cnt]=edge(to,v,head[from]);
head[from]=cnt;
e[++cnt]=edge(from,v,head[to]);
head[to]=cnt;
}
void init()
{
memset(head,-1,sizeof(head));
}
long long dis[2][510];
void spfa(int x)
{
deque<int> q;
bool used[510];
memset(used,0,sizeof(used));
memset(dis[x!=1],0x3f,sizeof(dis[x!=1]));
used[x]=1;
dis[x!=1][x]=0;
int flag=(x!=1);
q.push_back(x);
while(!q.empty())
{
int k=q.front();
q.pop_front();
used[k]=false;
for(int i=head[k];~i;i=e[i].nxt)
{
if(dis[flag][e[i].n]>dis[flag][k]+e[i].v)
{
dis[flag][e[i].n]=dis[flag][k]+e[i].v;
if(!used[e[i].n])
{
if(q.empty()||dis[flag][e[i].n]<dis[flag][q.front()])
q.push_front(e[i].n);
else
q.push_back(e[i].n);
used[e[i].n]=true;
}
}
}
}
}
}
int flow[510];
long long sum=0;//要开long long
namespace Flow
{
struct edge
{
int n,v;
int nxt;
edge(int n,int v,int nxt)
{
this->n=n;
this->v=v;
this->nxt=nxt;
}
edge()
{
nxt=-1;
}
}e[210000];
int head[505],cnt=-1;
void add(int from,int to,int v)
{
e[++cnt]=edge(to,v,head[from]);
head[from]=cnt;
e[++cnt]=edge(from,0,head[to]);
head[to]=cnt;
}
void init()
{
memset(head,-1,sizeof(head));
}
int d[505],gap[505];
void bfs(int x)
{
memset(d,0,sizeof(d));
int q[505],l=0,r=0;
q[++r]=x;
d[x]=1;
gap[0]=123456;
while(l<r)
{
int k=q[++l];
for(int i=head[k];~i;i=e[i].nxt)
{
if(!d[e[i].n])
{
d[e[i].n]=d[k]+1;
gap[d[e[i].n]]++;
q[++r]=e[i].n;
}
}
}
}
void isap(int x)
{
bfs(x);
int s=1;
int pre[505];
memset(pre,-1,sizeof(pre));
int cur[505];
for(int i=1;i<=x;i++)
cur[i]=head[i];
while(d[1]<=x)
{
if(s==x)
{
int minn=1234567890;
int p=pre[s];
while(~p)
{
minn=min(minn,e[p].v);
p=pre[e[p^1].n];
}
sum+=minn;
p=pre[s];
while(~p)
{
e[p].v-=minn;
e[p^1].v+=minn;
p=pre[e[p^1].n];
}
s=1;
}
int flag=0;
for(int i=cur[s];~i;i=e[i].nxt)
if(e[i].v&&d[e[i].n]+1==d[s])
{
pre[e[i].n]=i;
cur[s]=e[i].nxt;
flag=1;
s=e[i].n;
break;
}
if(flag==0)
{
int tmp=d[s];
d[s]=123456789;
for(int i=head[s];~i;i=e[i].nxt)
if(e[i].v)
d[s]=min(d[s],d[e[i].n]+1);
gap[tmp]--;
gap[d[s]]++;
if(gap[tmp]==0)
return;
cur[s]=head[s];
if(s!=1)
s=e[pre[s]^1].n;
}
}
}
}
int main()
{
using namespace graph;
init();
Flow::init();
int n,m,u,v,w;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(int i=1;i<=n;i++)
scanf("%d",&flow[i]);
flow[1]=1234567890;
flow[n]=1234567890;
spfa(1);
spfa(n);
for(int i=1;i<=n;i++)
for(int j=head[i];~j;j=e[j].nxt)
if(dis[0][i]+e[j].v+dis[1][e[j].n]==dis[0][n])
Flow::add(i,e[j].n,min(flow[i],flow[e[j].n]));
Flow::isap(n);
printf("%lld\n",sum);
return 0;
}
正解Code:
#include<cstdio>
#include<cstring>
#include<queue>
using std::deque;
int min(int x,int y)
{
return x<y?x:y;
}
long long min(long long x,long long y)
{
return x<y?x:y;
}
namespace graph
{
struct edge
{
int n;
int v;
int nxt;
edge(int n,int v,int nxt)
{
this->n=n;
this->v=v;
this->nxt=nxt;
}
edge()
{
nxt=-1;
}
}e[210000];
int head[501],cnt=-1;
void add(int from,int to,int v)
{
e[++cnt]=edge(to,v,head[from]);
head[from]=cnt;
e[++cnt]=edge(from,v,head[to]);
head[to]=cnt;
}
void init()
{
memset(head,-1,sizeof(head));
}
long long dis[2][510];
void spfa(int x)
{
deque<int> q;
bool used[510];
memset(used,0,sizeof(used));
memset(dis[x!=1],0x3f,sizeof(dis[x!=1]));
used[x]=1;
dis[x!=1][x]=0;
int flag=(x!=1);
q.push_back(x);
while(!q.empty())
{
int k=q.front();
q.pop_front();
used[k]=false;
for(int i=head[k];~i;i=e[i].nxt)
{
if(dis[flag][e[i].n]>dis[flag][k]+e[i].v)
{
dis[flag][e[i].n]=dis[flag][k]+e[i].v;
if(!used[e[i].n])
{
if(q.empty()||dis[flag][e[i].n]<dis[flag][q.front()])
q.push_front(e[i].n);
else
q.push_back(e[i].n);
used[e[i].n]=true;
}
}
}
}
}
}
long long flow[510];
long long sum=0;
namespace Flow
{
struct edge
{
int n;
long long v;
int nxt;
edge(int n,long long v,int nxt)
{
this->n=n;
this->v=v;
this->nxt=nxt;
}
edge()
{
nxt=-1;
}
}e[410000];
int head[1005],cnt=-1;
void add(int from,int to,long long v)
{
e[++cnt]=edge(to,v,head[from]);
head[from]=cnt;
e[++cnt]=edge(from,0,head[to]);
head[to]=cnt;
}
void init()
{
memset(head,-1,sizeof(head));
}
int d[1005],gap[1005];
void bfs(int x)
{
memset(d,0,sizeof(d));
int q[1005],l=0,r=0;
q[++r]=x;
d[x]=1;
gap[0]=123456;
while(l<r)
{
int k=q[++l];
for(int i=head[k];~i;i=e[i].nxt)
{
if(!d[e[i].n])
{
d[e[i].n]=d[k]+1;
gap[d[e[i].n]]++;
q[++r]=e[i].n;
}
}
}
}
void isap(int x)
{
bfs(x);
int s=1;
int pre[1005];
memset(pre,-1,sizeof(pre));
int cur[1005];
for(int i=1;i<=x;i++)
cur[i]=head[i];
while(d[1]<=x)
{
if(s==x)
{
long long minn=123456789000000;
int p=pre[s];
while(~p)
{
minn=min(minn,e[p].v);
p=pre[e[p^1].n];
}
sum+=minn;
p=pre[s];
while(~p)
{
e[p].v-=minn;
e[p^1].v+=minn;
p=pre[e[p^1].n];
}
s=1;
}
int flag=0;
for(int i=cur[s];~i;i=e[i].nxt)
if(e[i].v&&d[e[i].n]+1==d[s])
{
pre[e[i].n]=i;
cur[s]=e[i].nxt;
flag=1;
s=e[i].n;
break;
}
if(flag==0)
{
int tmp=d[s];
d[s]=x+1;
for(int i=head[s];~i;i=e[i].nxt)
if(e[i].v)
d[s]=min(d[s],d[e[i].n]+1);
gap[tmp]--;
gap[d[s]]++;
if(gap[tmp]==0)
return;
cur[s]=head[s];
if(s!=1)
s=e[pre[s]^1].n;
}
}
}
}
int main()
{
using namespace graph;
init();
Flow::init();
int n,m,u,v,w;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(int i=1;i<=n;i++)
scanf("%lld",&flow[i]);
flow[1]=12345678900000000;
flow[n]=12345678900000000;
spfa(1);
spfa(n);
for(int i=1;i<=n;i++)
{
Flow::add(i,500+i,flow[i]);
for(int j=head[i];~j;j=e[j].nxt)
if(dis[0][i]+e[j].v+dis[1][e[j].n]==dis[0][n])
Flow::add(500+i,e[j].n,12345678900000000);
}
Flow::isap(500+n);
printf("%lld\n",sum);
return 0;
}
说点什么