[最小割]JZOJ 3348 秘密任务
分析
建立在最短路条件上的题目,自然要先把最短路从图里面抠出来
然后可以发现是个最小割……由于一条边的拦截选择有两种,拆边即可
然后最难的是方案判断,在残量网络上比较不显然的一个结论是:
从s出发可到达的点集为S,可到达t的点集为T
如果一个边是最小割的一部分,当且仅当它的端点不完全属于一个集合并且它的出发一端不属于S或到达端不属于T,则方案不唯一
#include <iostream> #include <cstdio> #include <queue> #include <memory.h> using namespace std; typedef long long ll; const int N=4e2+10; const int M=4e3+10; const ll Inf=1ll<<62; struct Pipe { int v,nx; ll c; }e[8*M]; struct Graph { int v,nx; ll w; }g[2*M]; int cnt,list[N],lst[M+N]; ll dis[M+N],ans,a[N]; bool vis[N],p; int T,n,m,s,t; void Add_Pipe(int u,int v,ll c) { e[++cnt]=(Pipe){v,lst[u],c};lst[u]=cnt; e[++cnt]=(Pipe){u,lst[v],0};lst[v]=cnt; } void Add(int u,int v,ll w) { g[++cnt]=(Graph){v,list[u],w};list[u]=cnt; g[++cnt]=(Graph){u,list[v],w};list[v]=cnt; } void SPFA() { queue<int> q; while (!q.empty()) q.pop(); for (int i=1;i<=n;i++) dis[i]=Inf; memset(vis,0,sizeof vis); q.push(1);vis[1]=1;dis[1]=0; while (!q.empty()) { int u=q.front();q.pop(); for (int i=list[u];i;i=g[i].nx) if (dis[g[i].v]>dis[u]+g[i].w) { dis[g[i].v]=dis[u]+g[i].w; if (!vis[g[i].v]) q.push(g[i].v); vis[g[i].v]=1; } vis[u]=0; } } void BFS() { queue<int> q; while (!q.empty()) q.pop(); memset(lst,0,sizeof lst);memset(vis,0,sizeof vis); q.push(n);t=n;cnt=1; while (!q.empty()) { int u=q.front();q.pop(); for (int i=list[u];i;i=g[i].nx) if (dis[u]-g[i].w==dis[g[i].v]) { Add_Pipe(g[i].v,++t,a[g[i].v]);Add_Pipe(t,u,a[u]); if (!vis[g[i].v]) q.push(g[i].v); vis[g[i].v]=1; } } t=n; } bool BFS1() { queue<int> q; while (!q.empty()) q.pop(); memset(dis,0,sizeof dis); q.push(1);dis[1]=1; while (!q.empty()) { int u=q.front();q.pop(); for (int i=lst[u];i;i=e[i].nx) if (!dis[e[i].v]&&e[i].c) { dis[e[i].v]=dis[u]+1; q.push(e[i].v); } } return dis[t]; } ll Max_Flow(int u,ll mf) { ll ret=0; if (mf==0||u==t) return mf; for (int i=lst[u];i;i=e[i].nx) if (dis[e[i].v]==dis[u]+1&&e[i].c) { ll flow=Max_Flow(e[i].v,min(mf-ret,e[i].c)); e[i].c-=flow;e[i^1].c+=flow; ret+=flow; if (ret==mf) return ret; } return ret; } void DFS1(int u) { dis[u]=1; for (int i=lst[u];i;i=e[i].nx) if (!dis[e[i].v]&&e[i].c) DFS1(e[i].v); } void DFS2(int u) { dis[u]=2; for (int i=lst[u];i;i=e[i].nx) if (!dis[e[i].v]&&e[i^1].c) DFS2(e[i].v); } int main() { for (scanf("%d",&T);T;T--) { scanf("%d%d",&n,&m); memset(list,0,sizeof list);cnt=1; for (int i=1;i<n;i++) scanf("%lld",&a[i]);a[n]=Inf; for (int i=1,u,v;i<=m;i++) {ll w;scanf("%d%d%lld",&u,&v,&w),Add(u,v,w);} SPFA();BFS();s=1;ans=0; while (BFS1()) ans+=Max_Flow(s,Inf); memset(dis,0,sizeof dis);DFS1(s);DFS2(t); bool p=0; for (int i=2;i<=cnt;i+=2) if (!e[i].c&&dis[e[i^1].v]!=dis[e[i].v]&&(dis[e[i^1].v]!=dis[s]||dis[e[i].v]!=dis[t])) { printf("No %d\n",ans); p=1; break; } if (!p) printf("Yes %d\n",ans); } }
在日渐沉没的世界里,我发现了你。