[BZOJ1322]Destroying The Graph
阿新 • • 發佈:2018-07-13
bzoj names graph spa cap esp end 操作 網絡流
題目大意:
有一張有向圖,對於每個點,有兩種操作:
1. 刪掉它的所有入邊
2. 刪掉它的所有出邊
對每個點的每個操作均有不同的價值。
求使得圖上沒有邊的最小價值。
解題思路:
考慮把點拆成入點和出點,然後就是二分圖最小點權覆蓋集。
也可以考慮最小割。
從S到每個點的入點連容量為該點執行操作2的價值,每個點的出點到T連容量為該點執行操作1的價值。對於圖上的每條邊連容量inf的邊。
然後答案就是最小割(割一條S出發的邊,相當於執行了2操作,網絡流不可能從該點再流向其他節點,則相當於刪掉出邊。操作1同理)。
C++ Code:
#include<bits/stdc++.h> using namespace std; const int S=0,T=10005,inf=0x3fffffff; struct edge{ int to,nxt,cap; }e[200005]; int head[10050],cnt=1,n,m,level[10050],iter[10050]; inline void addedge(int from,int to,int flow){ e[++cnt]=(edge){to,head[from],flow}; head[from]=cnt; e[++cnt]=(edge){from,head[to],0}; head[to]=cnt; } queue<int>q; void bfs(){ level[S]=1; for(q.push(S);!q.empty();){ int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].nxt) if(e[i].cap&&!~level[e[i].to]){ level[e[i].to]=level[u]+1; q.push(e[i].to); } } } inline int min(int a,int b){return a<b?a:b;} int dfs(int u,int f){ if(!f||u==T)return f; for(int& i=iter[u];~i;i=e[i].nxt) if(e[i].cap&&level[e[i].to]>level[u]){ int d=dfs(e[i].to,min(f,e[i].cap)); if(d){ e[i].cap-=d; e[i^1].cap+=d; return d; }else level[e[i].to]=-1; } return 0; } int dinic(){ for(int flow=0,f;;){ memset(level,-1,sizeof iter); if(bfs(),!~level[T])return flow; memcpy(iter,head,sizeof iter); while(f=dfs(S,inf))flow+=f; } } int main(){ memset(head,-1,sizeof head); ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m; for(int i=1;i<=n;++i){ int p; cin>>p; addedge(i+n,T,p); } for(int i=1;i<=n;++i){ int p; cin>>p; addedge(S,i,p); } while(m--){ int x,y; cin>>x>>y; addedge(x,y+n,inf); } cout<<dinic()<<endl; return 0; }
[BZOJ1322]Destroying The Graph