https://codeforces.com/gym/101981/attachments
題意:n個人殺m個怪物,但每個人只能殺特定集合裏的怪,只能殺一個,但有K個藥水,喝了藥,每個騎士可以有且只有一次再殺一個。問最多殺多少個。
題解:最大流+建圖。(和隊友貪心做瘋狂WA)
建立三個虛點,一個超級源點連這n個人,一個超級終點連這m個怪,再把每個人對應集合裏的怪也連起來,容量都是1,有設一個點,左連超級源點,容量爲k,右連這n個人,容量爲1,然後跑最大流即可。
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
typedef long long ll;
const int N = 20005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
bool vis[N];
struct Edge{
int to;
ll cap, flow;
int next;//鄰接點,容量,流量,next
}edge[N*50];
int cnt;//n是點 m是邊 cnt是加邊操作後的邊
int head[N];//鄰接表
int dis[N];//分層 等級
int cur[N];//弧優化
void add(int u, int v, ll w){
edge[cnt] = (struct Edge){v, w, 0, head[u]};
head[u] = cnt++;
edge[cnt] = (struct Edge){u, 0, 0, head[v]};
head[v] = cnt++;
}
bool bfs(int start, int endd){//分層
memset(dis, -1, sizeof(dis));
memset(vis, false, sizeof(vis));
queue<int>que;
dis[start] = 0;
vis[start] = true;
que.push(start);
while(!que.empty()){
int u = que.front();
que.pop();
for(int i = head[u]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(!vis[E.to] && E.flow<E.cap){
dis[E.to] = dis[u]+1;
vis[E.to] = true;
if(E.to == endd) return true;
que.push(E.to);
}
}
}
return false;
}
ll dfs(int x, ll res, int endd){ //增廣
if(x == endd || res == 0) return res;
ll flow = 0, f;
for(int& i = cur[x]; i != -1; i = edge[i].next){
Edge E = edge[i];
if(dis[E.to] == dis[x]+1){
f = dfs(E.to, min(res, E.cap-E.flow), endd);
if(f>0){
edge[i].flow += f;
edge[i^1].flow -= f;
flow += f;
res -= f;
if(res == 0) break;
}
}
}
return flow;
}
ll max_flow(int start, int endd){
ll flow = 0;
while(bfs(start, endd)){
memcpy(cur, head, sizeof(head));//初始化弧優化數組
flow += dfs(start, INF, endd);
}
return flow;
}
void init(){//初始化
cnt = 0;
memset(head, -1, sizeof(head));
}
int main(){
init();
int n,m,k;
scanf("%d%d%d", &n, &m,&k);
int sp=0;//源點
int tp=n+m+1;//匯點
int mp=n+m+2;
add(sp,mp,k);
for(int i=1;i<=n;i++){
add(sp,i,1);
add(mp,i,1);
}
for(int i = 1; i <= m; i++){
add(n+i,tp,1);
}
for(int i=1;i<=n;i++){
int t; scanf("%d",&t);
while(t--){
int x; scanf("%d",&x);
add(i,n+x,1);
}
}
ll ans = max_flow(sp, tp);
printf("%lld\n", ans);
return 0;
}