题目链接: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());
}
}