一开始就觉得是最小割转最大流做,,没想出怎么建图。。其实也挺显然,将S向所有1的人连边,所有0的人像T连边,有边的连起双向边,对于一条S到T的路径S,u,v,T,割掉S-u表示u违背自己,代价为1,割掉u-v表示朋友冲突,代价为1,割掉v-T表示v违背自己,代价为1,所以就是最小割。。
#include<iostream>
#include<cstdio>
#define N 305
#define M 100005
#define inf 99999999
using namespace std;
struct edge{
int e,f,next;
}ed[M];
int n,m,q,s,e,ne=1,nd,i,a[N],d[N],u[N],que[N];
void add(int s,int e,int f)
{
ed[++ne].e=e;ed[ne].f=f;
ed[ne].next=a[s];a[s]=ne;
}
bool bfs(int s,int t)
{
int i,j,head=1,tail=1,get,to;
for (i=0;i<=nd;i++) u[i]=d[i]=0;
que[1]=s;u[s]=1;
while (head<=tail)
{
get=que[head++];
for (j=a[get];j;j=ed[j].next)
if (ed[j].f&&!u[to=ed[j].e])
{
d[to]=d[get]+1;
que[++tail]=to;
u[to]=1;
}
}
return d[t]!=0;
}
int extend(int x,int minf,int t)
{
int f=minf,del,j;
if (x==t) return minf;
for (j=a[x];j;j=ed[j].next)
if (ed[j].f&&d[ed[j].e]==d[x]+1)
{
del=extend(ed[j].e,min(minf,ed[j].f),t);
ed[j].f-=del;ed[j^1].f+=del;
minf-=del;
if(!minf) break;
}
if (f==minf) d[x]=0;
return f-minf;
}
int dinic(int s,int t)
{
int ans=0;
while (bfs(s,t)) ans+=extend(s,inf,t);
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
nd=n+1;
for (i=0;i<=nd;i++) a[i]=0;
for (i=1;i<=n;i++)
{
scanf("%d",&q);
if (q) add(0,i,1),add(i,0,0);else add(i,nd,1),add(nd,i,0);
}
for (i=1;i<=m;i++)
{
scanf("%d%d",&s,&e);
add(s,e,1);add(e,s,1);
}
printf("%d\n",dinic(0,nd));
}