[最小割][spfa][tarjan] Jzoj P3348 秘密任务
题解
- 这简直就是码农题,很少在比赛中切掉码农题了
- 先在原图里跑一遍最短路,然后把不在最短路里的边删掉
- 把其他的边,拆成起点和终点两个点,每个点为该点的点权,跑一遍最大流,这就是第一问
- 对于第二问,我们就是要最小割的唯一性判定
- 跑一遍tarjan对于一条满流边
- 如果起点与终点分属两个scc,那么它可以作为原图最小割的一条边
- 而当起点与S所在scc相同,终点与T所在scc相同时,这条边的选择是唯一的
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #define N 410 5 #define M 8010 6 #define P 100010 7 #define ll long long 8 using namespace std; 9 int n,m,T,cnt,tot,Scc,flag,top,p,q,s,t,head[N],last[N],cur[N],vis[N],Q[P],dfn[N],low[N],scc[N],val[N],stack[N]; 10 ll ans,dis[N]; 11 struct edge { int to,from,v,pre; }e[M],E[M*2]; 12 void insert(int x,int y,int v) 13 { 14 e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v; 15 e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=v; 16 } 17 void ins(int x,int y,int v) 18 { 19 E[++tot].to=y,E[tot].pre=x,E[tot].v=v,E[tot].from=last[x],last[x]=tot; 20 E[++tot].to=x,E[tot].pre=y,E[tot].v=0,E[tot].from=last[y],last[y]=tot; 21 } 22 void spfa() 23 { 24 memset(dis,0x3f,sizeof(dis)),memset(vis,0,sizeof(vis)); 25 dis[1]=0,p=0,Q[q=1]=1,vis[1]=1; 26 while (p!=q) 27 { 28 int u=Q[(++p)%P]; vis[u]=0; 29 for (int i=head[u];i;i=e[i].from) 30 if (dis[e[i].to]>dis[u]+e[i].v) 31 { 32 dis[e[i].to]=dis[u]+e[i].v; 33 if (!vis[e[i].to]) vis[e[i].to]=1,Q[(++q)%P]=e[i].to; 34 } 35 } 36 } 37 void add(int x) 38 { 39 if (vis[x]) return; 40 vis[x]=1; 41 for (int i=head[x];i;i=e[i].from) if (dis[x]==dis[e[i].to]+e[i].v) ins(e[i].to,x,min(val[x],val[e[i].to])),add(e[i].to); 42 } 43 bool bfs() 44 { 45 memset(dis,-1,sizeof(dis)),p=q=0; 46 Q[++q]=s,dis[s]=1; 47 while (p<q) 48 { 49 int u=Q[++p]; 50 for (int i=last[u];i;i=E[i].from) 51 if (E[i].v&&dis[E[i].to]==-1) 52 { 53 dis[E[i].to]=dis[u]+1,Q[++q]=E[i].to; 54 if (t==E[i].to) return 1; 55 } 56 } 57 return 0; 58 } 59 int dfs(int x,ll maxf) 60 { 61 if (x==t) return maxf; 62 ll f=0,r; 63 for (int i=cur[x];i;i=E[i].from) 64 { 65 cur[x]=i; 66 if (E[i].v&&dis[E[i].to]==dis[x]+1) 67 { 68 r=dfs(E[i].to,min(maxf-f,(ll)E[i].v)),E[i].v-=r,E[i^1].v+=r,f+=r; 69 if (f==maxf) break; 70 } 71 } 72 if (!f) dis[x]=-1; 73 return f; 74 } 75 ll dinic() 76 { 77 ll r=0; 78 while (bfs()) memcpy(cur,last,sizeof(cur)),r+=dfs(s,1ll<<60); 79 return r; 80 } 81 void tarjan(int x) 82 { 83 dfn[x]=low[x]=++dfn[0],stack[++top]=x; 84 for (int i=last[x];i;i=E[i].from) 85 if (E[i].v) 86 { 87 if (!dfn[E[i].to]) tarjan(E[i].to),low[x]=min(low[x],low[E[i].to]); 88 else if (!scc[E[i].to]) low[x]=min(low[x],dfn[E[i].to]); 89 } 90 if (dfn[x]==low[x]) 91 { 92 Scc++; 93 for (int i;i!=x;) i=stack[top--],scc[i]=Scc; 94 } 95 } 96 int main() 97 { 98 for (scanf("%d",&T);T;T--) 99 { 100 tot=1,cnt=flag=Scc=top=0,memset(head,0,sizeof(head)),memset(last,0,sizeof(last)),memset(dfn,0,sizeof(dfn)),memset(low,0,sizeof(low)),memset(scc,0,sizeof(scc)); 101 scanf("%d%d",&n,&m); 102 for (int i=1;i<n;i++) scanf("%d",&val[i]); val[n]=1<<30; 103 for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z); 104 spfa(),s=1,t=n,add(n),ans=dinic(); 105 for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); 106 for (int i=2;i<=tot;i+=2) 107 if (!E[i].v) 108 { 109 if (scc[E[i].pre]!=scc[E[i].to]&&!(scc[E[i].pre]==scc[1]&&scc[E[i].to]==scc[n])) flag=1; 110 if (scc[E[i].pre]==scc[1]&&scc[E[i].to]==scc[n]&&val[E[i].pre]==val[E[i].to]) flag=1; 111 } 112 !flag?printf("Yes "):printf("No "); printf("%lld\n",ans); 113 } 114 }