这题,,纯纯的最大流,,
不过打印路径的时候有个小技巧,,可以直接从代表体型的点遍历他的所有边,,如果cap!=0(这是反向弧),就说明这条边为割边,,,然后就很方便的打印路径了
#include<iostream>
#include<map>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<set>
#include<string.h>
#include<string>
#include<vector>
#define MX 1111
#define INF 0x3f3f3f3f
#define mem(x,y) memset(x,y,sizeof(x))
#define FIN freopen("input.txt","r",stdin)
using namespace std;
int n,m;
int head[MX],rear;
struct Edge
{
int nxt,to,cap;
} edge[MX*MX];
void edge_init()
{
mem(head,-1);
rear=0;
}
void edge_add(int a,int b,int cap)
{
edge[rear].cap=cap;
edge[rear].to=b;
edge[rear].nxt=head[a];
head[a]=rear++;
}
bool vis[MX];
int d[MX],cur[MX];
bool BFS(int s,int t)
{
mem(vis,0);
queue<int> my;
my.push(s);
vis[s]=1;
d[s]=0;
d[t]=-1;
while(!my.empty())
{
int u=my.front();
my.pop();
for(int i=head[u]; ~i; i=edge[i].nxt)
{
int v=edge[i].to;
if(vis[v]||!edge[i].cap) continue;
d[v]=d[u]+1;
vis[v]=1;
my.push(v);
}
}
return d[t]!=-1;
}
int DFS(int x,int t,int a)
{
if(x==t||a==0) return a;
int flow=0,f;
for(int &i=cur[x]; ~i; i=edge[i].nxt)
{
int v=edge[i].to;
if(d[v]==d[x]+1&&(f=DFS(v,t,min(a,edge[i].cap))))
{
edge[i].cap-=f;
edge[i^1].cap+=f;
flow+=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int Dinic(int s,int t)
{
int flow=0;
while(BFS(s,t))
{
memcpy(cur,head,sizeof(head));
flow+=DFS(s,t,INF);
}
return flow;
}
int main()
{
FIN;
while(cin>>m>>n)
{
edge_init();
int sum=0;
for(int i=1; i<=m; i++)
{
int x;
scanf("%d",&x);
sum+=x;
edge_add(n+i,n+m+1,x);
edge_add(n+m+1,n+i,0);
}
for(int i=1; i<=n; i++)
{
edge_add(0,i,1);
edge_add(i,0,0);
int cnt;
scanf("%d",&cnt);
while(cnt--)
{
int x;
scanf("%d",&x);
edge_add(i,n+x,1);
edge_add(n+x,i,0);
}
}
if(Dinic(0,n+m+1)==sum)
{
for(int i=1; i<=m; i++)
{
printf("%d: ",i);
vector<int> ans;
for(int j=head[i+n]; ~j; j=edge[j].nxt) if(edge[j].cap)ans.push_back(edge[j].to);//cap!=0,说明这条为割边
for(int j=ans.size()-1; j>=0; j--) printf("%d%c",ans[j],j==0?'\n':' ');
}
}
else puts("No Solution!");
}
return 0;
}