四川省赛G.Party

来源:互联网 发布:淘宝网关键词排名查询 编辑:程序博客网 时间:2024/05/17 02:48

题目链接:http://acm.bnu.edu.cn/v3/contest_show.php?cid=6865#problem/G
题意:n只青蛙,要么只喝绿茶,要么只喝红茶,要么两种茶都能接受,还有m个憎恶关系,互相憎恶的两只青蛙不能喝同一种茶,憎恶关系构成的图保证是一张二分图,当然,你还可以选择花费w[i]的代价删掉某只青蛙。问最少需要花费多少代价。

分析:题目问最小代价,给出的又是憎恶关系,容易想到最小割,关键是建图比较难想。首先,题目保证是二分图,可以对他黑白染色。假设没有两种茶都能喝的青蛙,那么只要对有边的且能喝茶种类相同的青蛙建边,流量连INF,跑最小割即可。现在考虑能喝两种茶的青蛙,假设他是白色的,那么可以将他拆成白红和白绿两个点,显然,白红只可能和黑红连边,白绿只可能和黑绿连边,因此我们可以考虑在左边放白绿/黑红,右侧放白红/黑绿,中间放置被拆成两个点的两种茶都能喝的青蛙,注意两种茶都能喝的青蛙之间可能有憎恶关系,我们把割边的流量设置在拆出的两个点之间,为了能让拆出两个点之间的流量起作用(选择这条边当割边就意味着删掉这只青蛙),需要从拆出的点中右侧的点连向左侧,这样就能保证删除起到了效果,具体还是要看下代码。

#include<bits/stdc++.h>using namespace std;typedef pair<int,int>pi;const int Inf=2e9,Maxn=1020*3,Maxe=320000;int n,m,s,t,ne;int val[Maxn],p[Maxn],col[Maxn],id[Maxn],h[Maxn];int cur[Maxn];vector<int>G1[Maxn];vector<int>G[Maxn];void dfs1(int u,int C){    col[u]=C;    for(int i=0;i<G1[u].size();i++)    {        int v=G1[u][i];if(col[v])continue;        dfs1(v,3-C);    }}pi e[Maxe];void add(int u,int v,int w){    e[ne]=pi(v,w);    G[u].push_back(ne++);    e[ne]=pi(u,0);    G[v].push_back(ne++);}bool bfs(){    queue<int>q;    for(int i=s;i<=t;i++)h[i]=Inf;    h[s]=0;    q.push(s);    while(!q.empty())    {        int u=q.front();q.pop();        for(int i=0;i<G[u].size();i++)        {            int v=e[G[u][i]].first,w=e[G[u][i]].second;            if(!w||h[v]!=Inf)continue;            h[v]=h[u]+1;            q.push(v);        }    }    return h[t]!=Inf;}int dfs(int u,int a){    if(u==t||!a)return a;    int ret=0;    for(int &i=cur[u];i<G[u].size();i++)    {        int v=e[G[u][i]].first,w=e[G[u][i]].second;        if(h[v]!=h[u]+1||!w)continue;        int b=dfs(v,min(a,w));        e[G[u][i]].second-=b;        e[G[u][i]^1].second+=b;        ret+=b;        a-=b;    }    return ret;}int dinic(){    for(int i=s;i<=t;i++)cur[i]=0;    int ret=0;    while(bfs())    {        for(int i=s;i<=t;i++)cur[i]=0;        ret+=dfs(s,Inf);    }    return ret;}int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        for(int i=1;i<=n;i++)scanf("%d",val+i);        for(int i=1;i<=n;i++)G1[i].clear();        for(int i=1;i<=n;i++)scanf("%d",p+i);        for(int i=0;i<m;i++)        {            int u,v;scanf("%d%d",&u,&v);            G1[u].push_back(v);            G1[v].push_back(u);        }        for(int i=1;i<=n;i++)col[i]=0;        for(int i=1;i<=n;i++)        {            if(!col[i])dfs1(i,1);        }        //for(int i=1;i<=n;i++)printf("%d ",col[i]);puts("");        ne=s=0;        t=n+1;        for(int i=1;i<=n;i++)        {            if(p[i]==3)            {                id[i]=t++;            }        }        for(int i=s;i<=t;i++)G[i].clear();        if(t>=Maxn)while(1);        for(int i=1;i<=n;i++)        {            if(p[i]<3)            {                if(col[i]==p[i])                {                    //printf("u=%d\n",i);                    add(s,i,val[i]);                    for(int j=0;j<G1[i].size();j++)                    {                        int v=G1[i][j];                        if(p[v]==3)add(i,v,Inf);                        else if(p[v]!=col[v])add(i,v,Inf);                    }                }                else                {                    add(i,t,val[i]);                    //if(i==1)printf("t=%d\n",t);                    for(int j=0;j<G1[i].size();j++)                    {                        int v=G1[i][j];                        if(p[v]==3)add(id[v],i,Inf);                    }                }            }            else             {                add(i,id[i],val[i]);                for(int j=0;j<G1[i].size();j++)                {                    int v=G1[i][j];                    if(p[v]==3)add(id[v],i,Inf);                }            }        }        //for(int i=1;i<=n;i++)printf("%d ",col[i]);puts("");    /*          for(int i=s;i<=t;i++)        {            printf("point%d:\n",i);            for(int j=0;j<G[i].size();j++)            {                printf("to=%d w=%d\n",e[G[i][j]].first,e[G[i][j]].second);            }            puts("");        }    */          printf("%d\n",dinic());    }}
0 0