题面:传送门
这道题要求两个答案,首先,我们先看第一个,求出最短时间,那跑一遍最短路不就行了吗?由于 ,所以什么方法都能过(除非把floyd写成 )。
第二个问题要求删去一些带权无向边,使新图的 的最短路长度大于原图的 的最短路长度,并求出删去的最小边权和。看到“最小”两个字,一般不是动态规划,就是网络流,这道题动态规划显然不可行,那我们往网络流上考虑。由于只有删去最短路上的边才能使最短路长度变大。我们可以先求出哪些边在最短路上。那怎么球呢?令 为 的最短路长度, 为 的边的长度,那么对于边 ,如果有
那么这条边一定在一条最短路里。我们将所有的这种边求出来,就得到了一个图,这时我们以删去的代价为边的流量,跑一遍最小割不就行了吗?这时可能有人会问,如果对于一条无向边,它的正反两条边都在最短路图里,并且全删了,代价会被多算一遍吗?其实仔细分析一下会发现,一条边是不可能正反两次都出现在最短路里的,假设对于无向边 , 出现在了最短路中, 也出现在了最短路中,则
那么
又
所以不符事实,不存在均出现在最短路中的情况。
因为有网络流,所以时间复杂度就不在此赘述了。。。
各位觉得我的分析清楚吗?如果觉得好的话,给个好评撒~~~
再给个代码理解下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
int n,m;
int p[130000],q[130000],t[130000],c[130000];
int ds[510],dt[510];
vector<pair<int,int> >g[510];
struct edge{
int to,cap,rev;
};
vector<edge>G[510];
void addedge(int frm,int to,int cap)
{
G[frm].push_back((edge){to,cap,G[to].size()});
G[to].push_back((edge){frm,0,G[frm].size()-1});
}
int lev[510],iter[510];
void bfs(int s,int t)
{
memset(lev,-1,sizeof(lev));
lev[s]=0;
int q[510];
int head=0,tail=1;
q[1]=s;
while(head<tail)
{
int x=q[++head];
if(x==t)return;
for(int i=0;i<G[x].size();i++)
{
edge &e=G[x][i];
if(e.cap && lev[e.to]<0)
{
lev[e.to]=lev[x]+1;
q[++tail]=e.to;
}
}
}
}
int dfs(int s,int t,int f)
{
if(s==t)return f;
for(int &i=iter[s];i<G[s].size();i++)
{
edge &e=G[s][i];
if(e.cap && lev[e.to]==lev[s]+1)
{
int d=dfs(e.to,t,min(f,e.cap));
if(d)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int mxflow(int s,int t)
{
int res=0;
for(;;)
{
bfs(s,t);
if(lev[t]<0)return res;
memset(iter,0,sizeof(iter));
int f;
while(f=dfs(s,t,1e9))res+=f;
}
}
void dijk(int x,int dis[])
{
priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> > >q;
bool vis[510];
for(int i=1;i<=n;i++)vis[i]=false;
for(int i=1;i<=n;i++)dis[i]=1e9;
dis[x]=0;
q.push(make_pair(0,x));
for(int i=1;i<=n;i++)
{
while(!q.empty() && (vis[q.top().second] || dis[q.top().second]!=q.top().first))q.pop();
int x=q.top().second;
q.pop();
for(int i=0;i<g[x].size();i++)
{
int y=g[x][i].first,w=g[x][i].second;
if(vis[y])continue;
if(dis[x]+w<dis[y])
{
dis[y]=dis[x]+w;
q.push(make_pair(dis[y],y));
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",p+i,q+i,t+i,c+i);
g[p[i]].push_back(make_pair(q[i],t[i]));
g[q[i]].push_back(make_pair(p[i],t[i]));
}
dijk(1,ds);
dijk(n,dt);
for(int i=1;i<=m;i++)
{
if(ds[p[i]]+t[i]+dt[q[i]]==ds[n])addedge(p[i],q[i],c[i]);
if(ds[q[i]]+t[i]+dt[p[i]]==ds[n])addedge(q[i],p[i],c[i]);
}
printf("%d\n%d",ds[n],mxflow(1,n));
return 0;
}