hdu3416+hdu6582(最短路+最大流)
题意
hdu3416:
给一个图,边不能重复选,问有多少个最短路
hdu6582:
给一个图,问最少删除边权多少的边后,最短路长度增加
分析
边不能重复选这个条件可以想到边权为1,跑最大流,所以我们可以先跑出最短路,再把最短路中的边作为网络流中的边跑一遍最大流即可。
最短路长度增加即最短路这个子图不再联通,要使一个图不再联通的最小代价显然就是最小割,也等于最大流。
找出最短路中的边的方法是从s正着跑一遍最短路,再从t逆着跑一遍最短路,如果\(low[u]+rev[v]+w==low[t]\),则\((u,v)\)为最短路中的边。
代码(hdu6582)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+50;
const ll INF=1e18;
int T,n,m;
int uu[N],vv[N];
ll ww[N];
vector<pair<int,int> > g[N];
ll low[N],rev[N];
bool vis[N];
struct node{
int v;
ll c;
bool operator<(const node &rhs)const{
return c>rhs.c;
}
};
void dijkstra(int s,ll low[]){
for(int i=1;i<=n;i++){
low[i]=INF;
vis[i]=false;
}
low[s]=0;
priority_queue<node> pq;
pq.push(node{s,low[s]});
while(!pq.empty()){
node tmp=pq.top();
pq.pop();
int u=tmp.v;
if(vis[u]){
continue;
}
vis[u]=true;
int siz=g[u].size();
for(int i=0;i<siz;i++){
int v=g[u][i].first;
ll w=g[u][i].second;
if(!vis[v] && low[v]>low[u]+w){
low[v]=low[u]+w;
pq.push(node{v,low[v]});
}
}
}
}
struct Edge{
int v,w,next;
}edge[N*2];
int cnt,head[N];
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
edge[cnt]=Edge{v,w,head[u]};
head[u]=cnt++;
edge[cnt]=Edge{u,0,head[v]};
head[v]=cnt++;
}
int dep[N];
bool bfs(){
memset(dep,0,sizeof(dep));
dep[1]=1;
queue<int> q;
q.push(1);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
ll w=edge[i].w;
if(w>0 && dep[v]==0){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return dep[n]!=0;
}
int cur[N];
ll dfs(int u,ll flow){
if(u==n){
return flow;
}
for(int &i=cur[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
ll w=edge[i].w;
if(dep[v]==dep[u]+1 && w>0){
int dis=dfs(v,min(w,flow));
if(dis>0){
edge[i].w-=dis;
edge[i^1].w+=dis;
return dis;
}
}
}
return 0;
}
ll dinic(){
ll ans=0;
while(bfs()){
for(int i=1;i<=n;i++){
cur[i]=head[i];
}
while(ll d=dfs(1,INF)){
ans+=d;
}
}
return ans;
}
int main(void){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
g[i].clear();
}
for(int i=0;i<m;i++){
scanf("%d%d%lld",&uu[i],&vv[i],&ww[i]);
g[uu[i]].push_back({vv[i],ww[i]});
}
dijkstra(1,low);
for(int i=1;i<=n;i++){
g[i].clear();
}
for(int i=0;i<m;i++){
g[vv[i]].push_back({uu[i],ww[i]});
}
dijkstra(n,rev);
init();
for(int i=0;i<m;i++){
if(uu[i]!=vv[i] && low[uu[i]]+rev[vv[i]]+ww[i]==low[n]){
add(uu[i],vv[i],ww[i]);
}
}
ll ans=dinic();
printf("%lld\n",ans);
}
return 0;
}