题意:
N 个城堡守卫正在就非洲的燕子能否搬运椰子而进行投票。每个人都有自己的看法,但是为了避免跟自己的朋友持相反意见,他们
时常会投相反的票。现在给出每个人的初始看法以及朋友关系,求在某种投票方案下, 违背自己意愿的票数与持不同意见的朋友对数的总和最小。 (2 <= N <= 300,1 <= M <= N(N-1)/2)
思路:
和spoj 839比较类似,S和原来为0的点连边,t和原来为1的点,原来的边(u,v)->大的多个addedge(u,v,1),addedge(v,u,1),求最小割就可以了我们再来考虑一下最小割的意义,割边如果是与s或者t相连,那么表示这个点变色,如果不是,表示两边的颜色都不变
拓展:假设求E(x1,x2,…,xn)=∑(1−xi)∗|pi−v0|+∑xi∗|pi−v1|+∑|xi−xj|∗|pi−pj|的最小值,pi,v0,v1均为常数,xi∈0,1
二者取一问题,把前两项合起来考虑就会发现,要么xi=0并获得一个|pi−v0| ,
xi=1,获得一个|pi−v1|;如果xi,xj取不同值时获得一个|pi−pj|。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define MP(x,y) make_pair(x,y)
typedef long long ll;
void fre() { freopen("input.in", "r", stdin); freopen("output.out", "w", stdout); }
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int maxn=310;
const int MAXM=1001000;
int head[maxn],tot,cur[maxn];
struct Edge{
int to,next,cap,flow;
}e[MAXM];
int d[maxn],gap[maxn],N,S[MAXM];
void init(int n){
memset(head,-1,sizeof(head));
tot=0;
N=n;
}
void addedge(int from,int to,int w){
e[tot].to=to,e[tot].next=head[from];
e[tot].cap=w,e[tot].flow=0;
head[from]=tot++;
e[tot].to=from,e[tot].next=head[to];
e[tot].cap=0,e[tot].flow=0;
head[to]=tot++;
}
void bfs(int st){
memset(d,-1,sizeof(d));
memset(gap,0,sizeof(gap));
d[st]=0,gap[0]=1;
queue<int>Q;
Q.push(st);
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(d[v]!=-1)
continue;
d[v]=d[u]+1;
gap[d[v]]++;
Q.push(v);
}
}
}
int sap(int st,int ed){
memcpy(cur,head,sizeof(head));
bfs(ed);
int u=st,top=0,ans=0;
while(d[st]<N){
if(u==ed){
int Min=INF,ind;
for(int i=0;i<top;i++){
if(Min>e[S[i]].cap-e[S[i]].flow){
Min=e[S[i]].cap-e[S[i]].flow;
ind=i;
}
}
for(int i=0;i<top;i++){
e[S[i]].flow+=Min;
e[S[i]^1].flow-=Min;
}
top=ind;
u=e[S[top]^1].to;
ans+=Min;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-1;i=e[i].next){
v=e[i].to;
if(e[i].cap>e[i].flow&&d[v]+1==d[u]){
flag=true;
cur[u]=i;
break;
}
}
if(flag){
S[top++]=cur[u];
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-1;i=e[i].next){
v=e[i].to;
if(e[i].cap>e[i].flow&&d[v]<Min){
Min=d[v];
cur[u]=i;
}
}
gap[d[u]]--;
if(gap[d[u]]==0)
return ans;
d[u]=Min+1;
gap[d[u]]++;
if(u!=st)
u=e[S[--top]^1].to;
}
return ans;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0&&m==0)
break;
int s=0,t=n+1,x,u,v;
init(t+1);
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==0)
addedge(s,i,1);
else
addedge(i,t,1);
}
for(int i=1;i<=m;i++)
scanf("%d%d",&u,&v),addedge(u,v,1),addedge(v,u,1);
printf("%d\n",sap(s,t));
}
return 0;
}