UVA 10779 Collectors Problem[最大流]

from:neopenxios

題目大意:Bob有一些貼紙,他能夠和別人交換,他能夠把本身獨有的貼紙拿出去,也能夠把重複的貼紙拿出去(有時候把獨有的貼紙而不是重複的貼紙拿出去能換到更多貼紙)。網絡

              Bob的朋友也有一些貼紙,可是他們只會拿本身重複的貼紙和Bob換,並且換的是本身沒有的貼紙。spa

              求Bob最後最多能有多少種貼紙。code

解題思路blog

題目意思很明確了。就算把重複的貼紙拿出去也不必定最優,貪心就不用嘗試了。資源

全局資源調配得使用網絡流模型。get

建圖方式:string

①S點(看做是Bob)->全部物品:連一條邊,cap是Bob持有貼紙數量。io

②:全部朋友->全部物品:若是這我的持有的該貼紙數量>=2,連一條邊,cap是貼紙數量-1。(緣由是這些人只會把重複的貼紙拿出去)。class

③:全部物品->全部朋友:若是這我的沒有改物品,連一條邊,cap=1,。(緣由是這些人會接受本身沒有的貼紙)

④:全部物品->T點:連一條邊,cap=1,統計物品的種類。

 

這樣建圖以後,全部物品能夠看做Bob的總資產,這個總資產能夠流進,也能夠流出,在這基礎上作一次最大流,就是結果了。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=700;
struct edge{int v,next,cap;}e[N<<1];int tot=1,head[N];
int n,m,cas,Cas,S,T,dis[N],q[N],a[11][26];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void add(int x,int y,int z){
    e[++tot].v=y;e[tot].cap=z;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].next=head[y];head[y]=tot;
}
inline bool bfs(){
    for(int i=S;i<=T;i++) dis[i]=-1;
    int h=0,t=1;q[t]=S;dis[S]=0;
    while(h!=t){
        int x=q[++h];
        for(int i=head[x];i;i=e[i].next){
            if(e[i].cap&&dis[e[i].v]==-1){
                dis[e[i].v]=dis[x]+1;
                if(e[i].v==T) return 1;
                q[++t]=e[i].v;
            }
        }
    }
    return 0;
}
int dfs(int x,int f){
    if(x==T) return f;
    int used=0,t;
    for(int i=head[x];i;i=e[i].next){
        if(e[i].cap&&dis[e[i].v]==dis[x]+1){
            t=dfs(e[i].v,min(e[i].cap,f));
            e[i].cap-=t;e[i^1].cap+=t;
            used+=t;f-=t;
            if(!f) return used;
        }
    }
    if(!used) dis[x]=-1;
    return used;
}
inline int dinic(){
    int res=0;
    while(bfs()) res+=dfs(S,2e9);
    return res;
}
int main(){
    cas=read();
    while(cas--){
        tot=1;memset(a,0,sizeof a);
        memset(head,0,sizeof head);
        n=read();m=read();
        for(int i=1,k,x;i<=n;i++){
            k=read();
            while(k--){
                x=read();
                a[i][x]++;
            }
        }
        S=0;T=n+m+1;
        for(int i=1;i<=m;i++){
            add(S,i,a[1][i]);
            add(i,T,1);
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]>=2) add(i+m,j,a[i][j]-1);
                if(!a[i][j]) add(j,i+m,1);
            }
        }
        printf("Case #%d: %d\n",++Cas,dinic());
    }
    return 0;
}
相關文章
相關標籤/搜索