Codeforces Educational Round#21 F(808F) Solution:网络流(最小割)

来源:互联网 发布:软件开发咨询 编辑:程序博客网 时间:2024/05/23 15:06

题意:给出一组卡牌(100张),卡牌有三个属性值:power,c,level,其中c和level是用来限制的,power是目标值。

具体的限制规则是:只有level小于等于玩家的playerlevel的卡牌才可以使用,任意两张c之和为prime的卡牌不能同时使用。

求出一个人物的最小等级,使得可以找到一个方案使得选用的卡牌的power值累计大于等于k。


这个题很容易想到二分playerlevel,然后关键在于已知playerlevel的时候,如何计算可以得到的最大的power。

Solution是使用maxFlow,这算是一个网络流建图题。

首先可以预处理出所有相互冲突的卡牌。如果在他们之间连接一条边,就构成了一个冲突网络。显而易见:一条边的两个端点一定是一个奇数一个偶数。

那么可以把节点归为偶数的点和奇数的点。现在的问题是,要去掉一些点,使得网络为空。下面讲解建图技巧。


构造一个偶数超源102点,一个奇数超汇101点,102点会和每一个偶数点连一条指向偶数点的边,边的容量是偶数点的power,101点会和每个技术点连一条指向101点的边,容量为奇数点的power。然后再冲突的奇偶点之间连接从偶数点指向奇数点的边,容量是INF。建图完成。


那么首先这张初始图上的总power值就是各个奇偶点的power之和,然后下面开始“去掉一些点,使得不存在冲突关系”。


从101到102跑一次maxFlow可以得到这个冲突网络的最大流,也就是最小割。那么考虑这个最小割的实际意义:划定一个边集,这个边集可以将冲突网络分成不想连的两部分,且我这个边集的边权之和最小,那么显然,我们的那些冲突边不可能出现在这里边, 因为他们都是INF,因此,显而易见,这个最小割当然就是我们要得到的答案。因为割掉这些边之后,我们就不存在一条经过102-偶数点-冲突边-奇数点-101的流了,也就是说,要么奇数点-101的边被割了,要么偶数点-102的边被割了,要么同时被割了(可能存在多重冲突情况,需要两个点都割),这样就能保证网络变得合法而不冲突,而且最小割也保证了这是代价最小的割,因此就是我们要的答案。


格外要注意1的情形,1虽然属于奇数点,但是考虑出现多个1的时候,这些1都是“奇数”,但是任意两个1之间也存在冲突关系,但是上面我们只考虑了从超源102-超汇101之间要没有带冲突的流,而没有考虑1-1之间这个冲突边,所以不能同时出现多个1在我们的图中,这个也很好处理,显然,在我们的卡组中,至多会有一张c=1的牌,所以建图的时候,先遍历一次得到我可以使用的power最大的那个c=1的牌,而把剩下其他的c=1的牌都舍弃掉就可以了。


注:dinic不需要反向弧


AC代码(需要改动):

#include<bits/stdc++.h>using namespace std;#define MAXN 105#define MAXM 100005int first[MAXN],nxt[MAXM],dis[MAXM],cont[MAXM];int m,n,k,s,t,tot;int p[MAXN],c[MAXN],l[MAXN];bool prm[200005];int deep[MAXN];int que[MAXN*10];bool hasEdge[MAXN][MAXN];int maxone=-1;int maxoneindex=-1;bool bfs(){    int l=0,r=1;    que[1]=s;    memset(deep,0,sizeof(deep));    while (l<r){        l++;        int q = que[l];        int tt=first[q];        while (tt!=-1){            if (dis[tt]!=s&&cont[tt]>0&&deep[dis[tt]]==0){                deep[dis[tt]]=deep[q]+1;                r++;                que[r]=dis[tt];            }            tt=nxt[tt];        }    }    if (deep[t]==0){        return false;    }else{            return true;    }}int dfs(int now,int limit){    if (now==t||limit==0){        return limit;    }    if (limit<=0){        return 0;    }    int flow=0,f;    int tt=first[now];    while (tt!=-1){        if (deep[dis[tt]]-deep[now]==1){            int temp = dfs(dis[tt],min(limit,cont[tt]));            cont[tt]-=temp;            cont[tt^1]+=temp;            limit-=temp;            flow+=temp;            if (limit==0){                break;            }        }        tt=nxt[tt];    }    return flow;}int maxFlow(int least){    tot=-1;    for (int i=0;i<103;i++){        first[i]=-1;    }    for (int i=0;i<n;i++){        for (int j=i+1;j<n;j++){            if (c[i]==1&&i!=maxoneindex){                continue;            }            if (c[j]==1&&j!=maxoneindex){                continue;            }            if (hasEdge[i][j]&&l[i]<=least&&l[j]<=least){                int ii,jj;                if (c[i]&1){                    ii=i;                    jj=j;                }else{                    ii=j;                    jj=i;                }                tot++;                cont[tot]=2147483647;                dis[tot]=jj;                nxt[tot]=first[ii];                first[ii]=tot;                tot++;                cont[tot]=0;                dis[tot]=ii;                nxt[tot]=first[jj];                first[jj]=tot;            }        }    }    int sum =0;    for (int i=0;i<n;i++){        if (c[i]==1&&i!=maxoneindex){            continue;        }        if (l[i]<=least){            sum+=p[i];            if (c[i]&1){                tot++;                cont[tot]=p[i];                dis[tot]=i;                nxt[tot]=first[101];                first[101]=tot;                tot++;                cont[tot]=p[i];                dis[tot]=101;                nxt[tot]=first[i];                first[i]=tot;            }else{                tot++;                cont[tot]=p[i];                dis[tot]=i;                nxt[tot]=first[102];                first[102]=tot;                tot++;                cont[tot]=p[i];                dis[tot]=102;                nxt[tot]=first[i];                first[i]=tot;            }        }    }    int ans =0;    while (bfs()){        ans+=dfs(s,2147483647);    }    return sum-ans;} int main(){    memset(prm,true,sizeof(prm));    prm[0]=prm[1]=false;    for (int i=2;i<200000;i++){        if (prm[i]){            int tmp=i<<1;            while (tmp<200000){                prm[tmp]=false;                tmp+=i;            }        }    }    cin>>n>>k;    memset(hasEdge,false,sizeof(hasEdge));    for (int i=0;i<n;i++){        cin>>p[i]>>c[i]>>l[i];        if (c[i]==1&&p[i]>maxone){            maxone=p[i];            maxoneindex=i;        }        for (int j=0;j<i;j++){            if (prm[c[i]+c[j]]){                hasEdge[i][j]=hasEdge[j][i]=true;            }        }    }    s=101;    t=102;        if (maxFlow(101)<k){        cout<<"-1"<<endl;        return 0;    }    int l=0;    int r=101;    while (r-l>1){        int mid =(l+r)>>1;        if (maxFlow(mid)>=k){            r=mid;        }else{            l=mid;        }    }    if (maxFlow(l)>=k){        cout<<l<<endl;    }else{        cout<<r<<endl;    }     return 0;}


阅读全文
0 0
原创粉丝点击