P2763 试题库问题
建图 : 添加 s = 0, t = n + k + 1; 加边 s--w---> (1-k) ; (n+1-n+k) --1---> t ; 对于每个 (1-n) --- (1-k) 根据所给的情况连边。然后跑最大流。
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 3000 + 10;
const int maxm = 100000 + 10;
int n,m,k;
int l[maxn];//记录层数
int h[maxn];//链式前向星
int cur[maxn];
int tot = 0;
struct edge
{
int to;
int c;
int next;
edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
}es[maxm*2];//记录边 注意是2倍
void add_edge(int u, int v, int c)
{
es[tot] = edge(v,c,h[u]);
h[u] = tot++;
es[tot] = edge(u,0,h[v]);
h[v] = tot++;
// cout << u <<" " <<v <<endl;
}
bool bfs(int s, int t)
{
memset(l,0,sizeof(l));
l[s] = 1;
queue <int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();
//cout << u <<endl;
q.pop();
if(u == t) return true;
for(int i = h[u]; i != -1; i = es[i].next)
{
int v = es[i].to;
if(!l[v] && es[i].c) {l[v] = l[u] + 1; q.push(v);}
}
}
return false;
}
int dfs(int x, int t, int mf)
{
if(x == t) return mf;
int ret = 0;
for(int &i = cur[x]; i != -1; i = es[i].next)
{
if(es[i].c && l[x] == l[es[i].to] - 1)
{
int f = dfs(es[i].to,t,min(es[i].c,mf - ret));
es[i].c -= f;
es[i^1].c += f;
ret += f;
if(ret == mf) return ret;
}
}
return ret;
}
int dinic(int s, int t)
{
int ans = 0;
while(bfs(s,t))
{
for(int i = 0; i <= t; i++) cur[i] = h[i];
ans += dfs(s,t,INF);
}
return ans;
}
int main()
{
scanf("%d%d",&k,&n);
tot = m = 0;
memset(h,-1,sizeof(h));
int s = 0, t = n+k+1;
for(int i = 1; i <= k; i++)
{
int x; scanf("%d",&x);
add_edge(s,i,x);
m += x;
}
for(int i = 1; i <= n; i++)
{
int p; scanf("%d",&p);
for(int j = 1; j <= p; j++)
{
int x; scanf("%d",&x);
add_edge(x,i+k,1);
}
add_edge(i+k,t,1);
}
int res = dinic(s,t);
cout << res <<endl;
if(res < m) printf("No Solution!\n");
else
for(int i = 1; i <= k; i++)
{
printf("%d: ",i);
vector <int> v;
for(int j = h[i]; ~j; j = es[j].next)
if(!es[j].c && es[j].to > k && es[j].to < t) v.push_back(es[j].to-k);
for(int j = 0; j < v.size(); j++)
printf("%d%c",v[j], j == v.size()-1? '\0':' ');
printf("\n");
}
return 0;
}