jzoj3348,bzoj3258-秘密任务【最短路,网络流最小割】
正題
題目鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=3258
題目大意
一張無向圖,路有邊權,在想要封鎖某條路可以在該路兩邊的任意一點設置檢查站(一個站只能封鎖一條路),在iii點建立一個檢查站要AiA_iAi?元。
求最少的費用封鎖所有的最短路徑,并詢問封鎖方案是否唯一
解題思路
先從111開始一遍最短路fff,然后從nnn開始再跑一次最短路f2f2f2
若一個點fx+f2x=fnf_x+f2_x=f_nfx?+f2x?=fn?那么該點是1~n1\sim n1~n的某條最短路上的一個點。
若一條邊fx+w=fyf_x+w=f_yfx?+w=fy?那么該邊是某條最短路上的邊。
然后我們將這些點和邊拿出來跑最小割即可求出第一問。
我們考慮如何求第二問,為了優化,我們發現每一條邊可以有兩個權值(在兩個檢查點中任何一個),所以我們將一條邊拆成兩條邊和一個中間點。
現在我們考慮求出最小割的必割邊,若這些必割邊的容量之和就是最小割那么這就是唯一的方案。
如何求出必割邊?
?*?結論:::對于一條邊x,yx,yx,y,在殘量網絡上sss可以到達xxx且yyy可以到達ttt那么該邊是必割邊。
證明:在殘量網絡上sss可以到達xxx且yyy可以到達ttt那么說明若該邊不割那么sss就可以通過該邊到達ttt。假設在sss到xxx的路上有同樣長度的一條道路且割掉后可以使sss到達xxx那么在殘量網絡上該邊的流量必定為0,因為切割掉x?>yx->yx?>y的流量也必定會經過該邊所以在殘量網絡上sss就不可以到達xxx了。所以該假設不成立。
證畢
所以我們在殘量網絡上跑兩次dfsdfsdfs然后一條一條邊的判斷即可。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=5010,inf=1e18; struct Edge_Node{ll to,next,w; }a[N*2],e[N*2]; ll T,ls[N],tot=1,n,m,c[N],f[N],dep[N],s,t,ans,cnt,flow,f2[N],get[N]; bool v[N]; queue<int> q; void adde(ll x,ll y,ll w) {a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0; } void addl(ll x,ll y,ll w) {e[++cnt].to=y;e[cnt].next=ls[x];ls[x]=cnt;e[cnt].w=w; } void spfa(ll s) {memset(f,127,sizeof(f));for(int i=1;i<=n;i++)f[i]=inf;q.push(s);f[s]=0;v[s]=1;while(!q.empty()){ll x=q.front();q.pop();v[x]=0;for(ll i=ls[x];i;i=e[i].next){ll y=e[i].to;if(f[x]+e[i].w<f[y]){f[y]=f[x]+e[i].w;if(!v[y])v[y]=1,q.push(y);}}} } void spfa2(ll s) {memset(f2,127,sizeof(f2));for(int i=1;i<=n;i++)f2[i]=inf;q.push(s);f2[s]=0;v[s]=1;while(!q.empty()){ll x=q.front();q.pop();v[x]=0;for(ll i=ls[x];i;i=e[i].next){ll y=e[i].to;if(f2[x]+e[i].w<f2[y]){f2[y]=f2[x]+e[i].w;if(!v[y])v[y]=1,q.push(y);}}} } bool bfs() {memset(dep,0,sizeof(dep));while(!q.empty()) q.pop();q.push(s);dep[s]=1;while(!q.empty()){ll x=q.front();q.pop();for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(!dep[y]&&a[i].w){dep[y]=dep[x]+1;if(y==t) return true;q.push(y);}}}return false; } ll dinic(ll x,ll flow) {ll rest=0,k;if(x==t) return flow;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(dep[x]+1==dep[y]&&a[i].w){rest+=(k=dinic(y,min(a[i].w,flow-rest)));a[i].w-=k;a[i^1].w+=k;if(rest==flow) return flow;}}if(!rest) dep[x]=0;return rest; } void netflow() {while(bfs())ans+=dinic(s,inf); } void dfs(ll x,ll op) {if(get[x]) return;get[x]=op;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(!a[i^(op-1)].w) continue;dfs(y,op);} } int main() {scanf("%lld",&T);while(T--){memset(ls,0,sizeof(ls));tot=cnt=1;scanf("%lld%lld",&n,&m);s=1;t=n;ans=flow=0;c[n]=inf;for(ll i=1;i<n;i++)scanf("%lld",&c[i]);for(ll i=1;i<=m;i++){ll x,y,w;scanf("%lld%lld%lld",&x,&y,&w);addl(x,y,w);addl(y,x,w);}spfa(1);spfa2(n);memset(ls,0,sizeof(ls));for(int i=1;i<=n;i++)get[i]=(f[i]+f2[i]==f[n]);for(ll i=2;i<=cnt;i++){ll x=e[i^1].to,y=e[i].to;if(!get[x]||!get[y]) continue;if(f[x]+e[i].w==f[y]){++n;adde(x,n,c[x]); adde(n,y,c[y]);}}netflow();memset(get,0,sizeof(get));dfs(1,1);dfs(t,2);for(ll i=1;i<=n;i++)for(ll j=ls[i];j;j=a[j].next)if(get[i]&&get[a[j].to]&&get[i]!=get[a[j].to])flow+=a[j].w;if(flow==ans) printf("Yes");else printf("No");printf(" %lld\n",ans);} }總結
以上是生活随笔為你收集整理的jzoj3348,bzoj3258-秘密任务【最短路,网络流最小割】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何限制他人操作自己的电脑怎么控制别人电
- 下一篇: jzoj3379-查询【主席树】