题目: http://acm.hdu.edu.cn/showproblem.php?pid=6582
题意:
给定一张有向图,n个点,m条边;
可以砍掉一些边,砍掉每条边的代价是边的权值;
问最少花费多少,能使得从1到n的最短路长度至少增加1,不连通也算长度增加。
输出最少花费。
分析:
1.总体思路
由于从1到n的最短路可能存在多条,所以需要先把所有最短路上的边拎出来建一张图G;
然后在图G上跑最小割,用最小的花费把源点1和汇点n割开,割开之后原图中所有原有最短路必然不联通,此时1~n的最短路长度必然增加;
因为“最小割=最大流”定理,所以只需要在图G上跑最大流算法即可。
2.建立图G
如何建立图G呢?
这相当于要找出从1到n的所有最短路。
如果在dijkstra中用vector记录每个节点的多个前驱节点(或边),有可能会MLE;
怎么办呢?
观察每一条边,如果其存在于从1到n的最短路上,那么满足式子:
dist[u]+cost[i]+dist2[v]==dist[n],
其中dist[j]是从1到j的最短路,cost[i]是第i条边的权值,dist2[j]是从j到n的最短路;
dist2是通过反向建图跑dijkstra得到的。
为了防止TLE,这里使用Heap+Dijkstra。
3.最大流
Dinic由于采用分层图、多路增广等策略,时间复杂度比其他网络流算法较优,其时间复杂度是O(n^2*m);
算起来仍然TLE,但网络流算法时间复杂度很奇怪,Dinic跑的很快,加上当前弧优化之后交就是了!
代码:
#include <bits/stdc++.h>
#define Pii pair<int,int>
using namespace std;
typedef long long llong;
const llong inf=1e16;
const int tmax=1e4+5,inf_int=1e9+5;
struct node {
llong d;
int x;
bool operator<(const node &b)const
{
return d>b.d;
}
};
int n,m,xx[tmax],yy[tmax],cc[tmax];
vector<Pii> GG[tmax];
priority_queue<node> Q;
bool vis[tmax];
llong dis[tmax],_dis[tmax];
void dijk(int s,llong *d)
{
int i,u,v,w,len;
node tmp;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++) d[i]=inf;
d[s]=0;
Q.push((node){0,s});
while(!Q.empty())
{
tmp=Q.top();
Q.pop();
u=tmp.x;
if(vis[u]) continue;
vis[u]=true;
len=GG[u].size();
for(i=0;i<len;i++)
{
v=GG[u][i].first;
w=GG[u][i].second;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
Q.push((node){d[v],v});
}
}
}
return;
}
struct edge{
int to,cap,rev;
};
vector<edge> G[tmax];
int level[tmax];
int iter[tmax];
void add(int from,int to,int cap)
{
G[from].push_back((edge){to,cap,G[to].size()});
G[to].push_back((edge){from,0,G[from].size()-1});
return;
}
void bfs(int s)
{
memset(level,-1,sizeof(level));
queue<int> que;
level[s]=0;
que.push(s);
while(!que.empty())
{
int v=que.front();
que.pop();
for(int i=0;i<G[v].size();i++)
{
edge &e=G[v][i];
if(e.cap>0&&level[e.to]<0)
{
level[e.to]=level[v]+1;
que.push(e.to);
}
}
}
return;
}
int dfs(int v,int t,int f)
{
if(v==t) return f;
for(int &i=iter[v];i<G[v].size();i++)
{
edge &e=G[v][i];
if(e.cap>0&&level[v]<level[e.to])
{
int d=dfs(e.to,t,min(f,e.cap));
if(d>0)
{
e.cap-=d;
G[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
int Dinic(int s,int t)
{
int flow=0;
while(1)
{
bfs(s);
if(level[t]<0) return flow;
memset(iter,0,sizeof(iter));
int f;
while((f=dfs(s,t,inf_int))>0)
flow+=f;
}
}
int main()
{
int TT,i;
scanf("%d",&TT);
while(TT--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&xx[i],&yy[i],&cc[i]);
GG[xx[i]].push_back(Pii(yy[i],cc[i]));
}
dijk(1,dis);
for(i=1;i<=n;i++)
GG[i].clear();
for(i=1;i<=m;i++)
GG[yy[i]].push_back(Pii(xx[i],cc[i]));
dijk(n,_dis);
for(i=1;i<=m;i++)
{
if(dis[xx[i]]+cc[i]+_dis[yy[i]]==dis[n])
add(xx[i],yy[i],cc[i]);
}
cout<<Dinic(1,n)<<endl;
for(i=1;i<=n;i++)
{
GG[i].clear();
G[i].clear();
}
}
return 0;
}