这也是这次多校相对比较简单的一道题。
对于一个无向图,正向spfa一遍,反向spfa一遍,然后求出它的最短路图,我的最短路图把方向也构建了出来,然后第一问只需要求一个最小割就行,第二问的话就把最短路图的边长全部赋为1然后再跑一遍spfa就可以。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct rec
{
int dis,num,w,next;
}e[5][151000];
struct rec2
{
int v,u,w;
}v[151000];
int n,m;
int link[5][3010],dist[5][3010],e_tot[5];
void insert(int x,int y,int z,int w)
{
if (w==1)
{
e_tot[w]++;e[w][e_tot[w]].num=y;e[w][e_tot[w]].w=z;e[w][e_tot[w]].next=link[w][x];link[w][x]=e_tot[w];
}
if (w==2)
{
e_tot[w]++;e[w][e_tot[w]].num=y;e[w][e_tot[w]].w=z;e[w][e_tot[w]].next=link[w][x];e[w][e_tot[w]].dis=e_tot[w]+1;
link[w][x]=e_tot[w];
e_tot[w]++;e[w][e_tot[w]].num=x;e[w][e_tot[w]].w=0;e[w][e_tot[w]].next=link[w][y];e[w][e_tot[w]].dis=e_tot[w]-1;
link[w][y]=e_tot[w];
e_tot[w+1]++;e[w+1][e_tot[w+1]].num=y;e[w+1][e_tot[w+1]].w=1;e[w+1][e_tot[w+1]].next=link[w+1][x];
link[w+1][x]=e_tot[w+1];
}
}
int head,tail;
int dui[2100];
bool flag[2100];
void spfa(int x,int w,int ww)
{
memset(flag,0,sizeof(flag));
head=0;
tail=1;
dui[tail]=x;
dist[w][x]=0;
flag[x]=1;
while(head!=tail){
head=(head+1)%(n+1);
int xx=dui[head];
for (int p=link[ww][xx];p;p=e[ww][p].next){
int j=e[ww][p].num;
if(dist[w][j]>dist[w][xx]+e[ww][p].w){
dist[w][j]=dist[w][xx]+e[ww][p].w;
if(!flag[j]){
flag[j]=1;
tail=(tail+1)%(n+1);
dui[tail]=j;
}
}
}
flag[xx]=0;
}
}
void make_net()
{
for (int i=1;i<=m;i++)
if ((dist[1][v[i].u]+dist[2][v[i].v]+v[i].w==dist[1][n])||(dist[1][v[i].v]+dist[2][v[i].u]+v[i].w==dist[1][n]))
{
if (dist[1][v[i].v]>dist[1][v[i].u]) insert(v[i].u,v[i].v,1,2);
else insert(v[i].v,v[i].u,1,2);
}
}
int h[3100],s[3100];
int dfs(int x,int total)
{
if (x==n) return total;
int minh=n-1,leave=total,w;
for (int p=link[2][x];p;p=e[2][p].next)
{
//printf("%d %d %d %d\n",x,total,p,e[p].num);
if (e[2][p].w>0)
{
if (h[x]==h[e[2][p].num]+1)
{
w=dfs(e[2][p].num,min(e[2][p].w,leave));
e[2][p].w-=w;
e[2][e[2][p].dis].w+=w;
leave-=w;
if (h[1]==n) return total-leave;
}
minh=min(h[e[2][p].num],minh);
}
}
if (leave==total)
{
s[h[x]]--;
if (s[h[x]]==0)
h[1]=n;
h[x]=minh+1;
s[h[x]]++;
}
return total-leave;
}
void network()
{
int ans=0;
memset(h,0,sizeof(h));
memset(s,0,sizeof(s));
s[0]=n;
while (h[1]<n)
ans+=dfs(1,200000000);
printf("%d ",ans);
}
void clean()
{
memset(dist,30,sizeof(dist));
memset(e,0,sizeof(e));
memset(link,0,sizeof(link));
memset(v,0,sizeof(v));
memset(e_tot,0,sizeof(e_tot));
}
int main()
{
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
while (scanf("%d%d",&n,&m)!=EOF)
{
clean();
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&v[i].u,&v[i].v,&v[i].w);
insert(v[i].u,v[i].v,v[i].w,1);
insert(v[i].v,v[i].u,v[i].w,1);
}
spfa(1,1,1);
spfa(n,2,1);
make_net();
network();
spfa(1,3,3);
printf("%d\n",m-dist[3][n]);
}
return 0;
}