大家在其他题解中看到的直接告诉你这个是什么类型的题目,用什么概念去求,让后就放代码,在这里我会用通俗易懂的话来讲这道题为什么这样建图。
读题可知一个事情,如果要使得可以让这个来拍照的人拍照只有两种可能性:
- 给的钱已经大于了所需要的属下需要的钱。
- 经过其他与之有交集(跟他有相同需要属下的人)的属下总共的和大于需要的属下总共需要的钱。
我们就可以将其题目转化成有 M M M 个人他们可以给某些属下发钱,他们有 N N N 个属下,其中每个属下想要的钱是固定的。我们可以让 M M M 个人中任意个数的人给他们想发钱的属下(可以不发满)如果全部属下都不能再收钱那么就将钱给你,求在每个属下都发满的前提下你能得到多少钱。
这样的话,我们就只需要假设这 M M M 个人都发钱,让后求每个人手上剩下的钱。这也就变成了求 N N N 个属下可以得到多少钱,之后让 M M M 个人能发的钱的总和减去 N N N 个属下总共能得到的钱就是本题的答案。
所以我们就可以用网络流来求解,将源点与拍照的人相连,流量为他们给的钱,再将他们与他们所需要的属下相连,流量为无穷大,最后将属下连向汇点。跑一个最大流,让 M M M 个人给的钱的总和减去最大流就为答案了。
代码
#include<bits/stdc++.h>
#define int long long
#define inf 2147483647
#define N 223
using namespace std ;
int n , m , head[N] , now[N] , cnt=0 , s , t , dep[N] , ans=0 , sum=0 ;
bool f[N] ;
struct node{
int to , next , w ;
}e[N<<12]; //谁会认真的算这个东西
void newnet(int u,int v,int w){
e[cnt].to = v ;
e[cnt].w = w ;
e[cnt].next = head[u] ;
head[u] = cnt++ ;
}
bool bfs(){
for(int i=1;i<=t;i++) dep[i] = inf , now[i] = head[i] , f[i] = 0 ;
queue<int> q ;
q.push(s) ;
dep[s] = 0 ;
while(!q.empty()){
int u=q.front() ;
q.pop() ;
f[u] = 0 ;
for(int i=head[u];~i;i=e[i].next){
int x=e[i].to ;
if(dep[u]+1<dep[x]&&e[i].w){
dep[x] = dep[u]+1 ;
if(!f[x]){
f[x] = 1 ;
q.push(x) ;
}
}
}
}
return dep[t]!=inf ;
}
int dfs(int u,int sum){
if(u==t) return sum ;
int use=0 ;
for(int i=now[u];~i;i=e[i].next){
now[u] = i ;
int x=e[i].to ;
if(dep[x]!=dep[u]+1||!e[i].w) continue ;
int temp=dfs(x,min(sum,e[i].w)) ;
if(!temp) continue ;
e[i].w -= temp ;
e[i^1].w += temp ;
use += temp ;
if(use==sum) break ;
}
return use ;
}
void dinic(){
while(bfs())
ans += dfs(s,inf) ;
cout << max(sum-ans,1ll*0) << endl ;
}
int read(){
int x=0 , f=1 ;
char a=getchar() ;
while(!(a>='0'&&a<='9')){
if(a=='-') f = -f ;
a = getchar() ;
}
while(a>='0'&&a<='9'){
x *= 10 ;
x += a-'0' ;
a = getchar() ;
}
return x ;
}
signed main(){
memset(head,-1,sizeof(head)) ;
cin >> m >> n ;
s = n+m+1 ;
t = s+1 ;
for(int i=1;i<=m;i++){
int c=read() , to ;
sum += c ;
newnet(s,i,c) ;
newnet(i,s,0) ;
while(to=read()){
newnet(i,m+to,inf) ;
newnet(m+to,i,0) ;
}
}
for(int i=1;i<=n;i++){
int c=read() ;
newnet(i+m,t,c) ;
newnet(t,i+m,0) ;
}
dinic() ;
return 0 ;
}
在最后祝在谷CS2玩家能像我一样,哥本哈根胶囊一发出粉