P2763 试题库问题(dinic)

P2763 试题库问题

dinic

搞个虚拟源点和汇点,瞎建建边就好辣。

偷张图↓↓

如果没满流就是无解辣

输出方案咋办呢?

枚举每种类型,蓝后枚举它们的边

如果该边被使用了(通过判断反向边的流量),且连接的另一点不是汇点

那么就找到一个被用的题了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
inline int Min(int a,int b){return a<b?a:b;}
void read(int &x){
    static char c=getchar();x=0;
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
}
#define N 1050
#define M 210000
int n,m,k,S,T,d[N],cur[N]; bool vis[N];
int cnt=1,hd[N],nxt[M],ed[N],poi[M],val[M];
queue <int> h;
void adde(int x,int y,int v){
    nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt;
    ed[x]=cnt; poi[cnt]=y; val[cnt]=v;
}
bool bfs(){
    memset(vis,0,sizeof(vis));
    h.push(S); vis[S]=1; d[S]=0;
    while(!h.empty()){
        int x=h.front(); h.pop();
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(!vis[to]&&val[i]>0){
                vis[to]=1; d[to]=d[x]+1;
                h.push(to);
            }
        }
    }return vis[T];
}
int dfs(int x,int a){
    if(x==T||a==0) return a;
    int f,F=0;
    for(int &i=cur[x];i&&a;i=nxt[i]){
        int to=poi[i];
        if(d[to]==d[x]+1&&(f=dfs(to,Min(a,val[i])))>0)
            a-=f,F+=f,val[i]-=f,val[i^1]+=f;
    }return F;
}
int dinic(){
    int re=0;
    while(bfs()){
        for(int i=1;i<=T;++i) cur[i]=hd[i];
        re+=dfs(S,1e9);
    }return re;
}
inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);}
int main(){
    read(k);read(n); register int i,j,q;
    S=n+k+1; T=S+1;
    for(i=1;i<=k;++i) read(q),m+=q,link(i+n,T,q);
    for(i=1;i<=n;++i){
        read(j); link(S,i,1);
        while(j--) read(q),link(i,q+n,1);
    }
    if(dinic()!=m){puts("No Solution!");return 0;}
    for(i=1;i<=k;++i){
        printf("%d:",i);
        for(j=hd[i+n];j;j=nxt[j])
            if(poi[j]!=T&&val[j])
                printf(" %d",poi[j]);
        printf("
");
    }return 0;
}
原文地址:https://www.cnblogs.com/kafuuchino/p/10575232.html