Time:2016.07.19
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
按照赞成与反对组成二分图
分别向s,t连边,流量为1
意见不同的朋友连边,流量为1
跑出的最大流即为答案
举例说明——若a,b是好朋友,a支持b反对,那么要么让a违心,割掉s->a的边,要么让b违心,割掉b->t的边,要么a,b相反,割掉a->b
注意:无
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
int n,m,tot=1,s,t;
int first[305],dis[305];
bool F[305];
struct edge{
int u,v,w,next;
}e[50000];
int in()
{
int t=0;char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void add(int x,int y,int z)
{
e[++tot]=(edge){x,y,z,first[x]};
first[x]=tot;
e[++tot]=(edge){y,x,0,first[y]};
first[y]=tot;
}
bool bfs()
{
queue<int>q;
memset(dis,0,sizeof(dis));
dis[s]=1;
q.push(s);
for (int k;!q.empty();q.pop())
{
k=q.front();
for (int i=first[k];i;i=e[i].next)
if (!dis[e[i].v]&&e[i].w)
dis[e[i].v]=dis[k]+1,
q.push(e[i].v);
}
return dis[t];
}
int dfs(int x,int mx)
{
if (x==t) return mx;
int used=0;
for (int i=first[x];i;i=e[i].next)
if (dis[e[i].v]==dis[x]+1)
{
int k=dfs(e[i].v,min(e[i].w,mx-used));
e[i].w-=k;e[i^1].w+=k;
used+=k;
if (used==mx) return used;
}
if (!used) dis[x]=0;
return used;
}
main()
{
n=in();m=in();
t=n+1;
for (int i=1;i<=n;i++)
{
F[i]=in();
if (F[i]) add(s,i,1);
else add(i,t,1);
}
int x,y;
for (int i=1;i<=m;i++)
{
x=in();y=in();
if (F[x]^F[y])
{
if (F[x]) add(x,y,1);
else add(y,x,1);
}
}
int ans=0;
while (bfs()) ans+=dfs(s,0x7fff);
printf("%d",ans);
}