P1791-[国家集训队]人员雇佣【最大权闭合图】
生活随笔
收集整理的這篇文章主要介紹了
P1791-[国家集训队]人员雇佣【最大权闭合图】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P1791
題目大意
有nnn個人,雇傭第iii個需要AiA_iAi?的費用,對于Ei,jE_{i,j}Ei,j?表示如果iii選了的話,選擇jjj會獲得Ei,jE_{i,j}Ei,j?的費用,不選jjj會花費Ei,jE_{i,j}Ei,j?的費用。
1≤n≤10001\leq n\leq 10001≤n≤1000
解題思路
考慮網最大權值閉合圖,先加上所有可以獲得的權值,然后考慮需要失去的最小權值。
因為每個人可以選或者不選,那么就可以讓sss連接iii且iii連接ttt這樣兩邊必須割掉一條表示選擇或者不選擇。
考慮讓s?>is->is?>i表示選擇,那么s?>is->is?>i權值為AiA_iAi?。
i?>ti->ti?>t表示不選擇那么所有由iii產生的費用都不能獲得,權值為∑j=1mEi,j\sum_{j=1}^mE_{i,j}∑j=1m?Ei,j?。
然后對于一個Ei,jE_{i,j}Ei,j?如果iii選擇了且jjj沒有選擇那么就會失去2×Ei,j2\times E_{i,j}2×Ei,j?的流量,在iii和jjj之間連一條2×Ei,j2\times E_{i,j}2×Ei,j?的就好了。
code
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=2e4+10,inf=2147483647; struct node{ll to,next,w; }a[N*4]; ll n,s,t,tot,cnt,A[N],ls[N],dep[N],ans; queue<int> q; void addl(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;return; } bool bfs(){memset(dep,0,sizeof(dep));dep[s]=1;while(!q.empty())q.pop();q.push(s);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)continue;dep[y]=dep[x]+1;if(y==t)return 1;q.push(y);}}return 0; } ll dinic(ll x,ll flow){if(x==t)return flow;ll rest=0,k;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(dep[y]!=dep[x]+1||!a[i].w)continue;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; } signed main() {scanf("%lld",&n);s=n+1;t=s+1;tot=1;for(ll i=1;i<=n;i++){ll x;scanf("%lld",&x);addl(s,i,x);}for(ll i=1;i<=n;i++){ll S=0;for(ll j=1;j<=n;j++){ll x;scanf("%lld",&x);if(!x)continue;S+=x;addl(i,j,2*x);}addl(i,t,S);ans+=S;}while(bfs())ans-=dinic(s,inf);printf("%lld\n",ans);return 0; }總結
以上是生活随笔為你收集整理的P1791-[国家集训队]人员雇佣【最大权闭合图】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我问我自己活着是为什么是什么歌 谁的心在
- 下一篇: CometOJ-[Contest #10