SHOI2007善意的投票
又是一道网络流
考虑用s表示同意,t表示不同意;
如果此人同意,就将他与s连一条边,否则与t连一条边;
还有,如果两人\((x,y)\)是朋友的话,就连一条\(x->y\)和\(y->x\)的边,因为只要一个人改变主意就可以了,不管是x还是y,所以连双向边;
这样连后,我们考虑最小割;
割掉一条\(s->x\)或\(x->t\)的边表示他改变了想法,要迁就别人,这样贡献就\(+1\);
如果割掉一条\(x->y\)的边,就代表x坚持自己的想法,朋友间的冲突\(++\);
这样,我们直接放心地跑最大流即可。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int maxN=1e6 + 100,inf=1e9;
struct Node
{
int to,value,next;
}edge[maxN*2+1];
int head[maxN+1],tot=1,n,m;
int cur[maxN+1],s,t,ans;
int dep[maxN+1];
int read()
{
int num=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48),ch=getchar();
return num*f;
}
void add(int x,int y,int t)
{
edge[++tot]=(Node){y,t,head[x]}; head[x]=tot;
edge[++tot]=(Node){x,0,head[y]}; head[y]=tot;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
queue<int> q;
dep[s]=1; q.push(s);
while(!q.empty())
{
int x=q.front(); q.pop();
for(int i=head[x];i;i=edge[i].next)
if(edge[i].value&&!dep[edge[i].to])
{
dep[edge[i].to]=dep[x]+1;
q.push(edge[i].to);
if(edge[i].to==t) return true;
}
}
return false;
}
int dfs(int x,int num)
{
if(x==t||!num) return num;
int sum=0;
for(int &i=cur[x];i;i=edge[i].next)
if(edge[i].value&&dep[edge[i].to]==dep[x]+1)
{
int tmp=dfs(edge[i].to,min(num,edge[i].value));
num-=tmp; sum+=tmp;
edge[i].value-=tmp; edge[i^1].value+=tmp;
if(!num) break;
}
return sum;
}
int main()
{
n=read(),m=read();
s=0,t=n+1;
for(int i=1;i<=n;i++)
if(read()) add(s,i,1);
else add(i,t,1);
while(m--)
{
int x=read(),y=read();
add(x,y,1); add(y,x,1);
}
while(bfs()) memcpy(cur,head,sizeof(head)),ans+=dfs(s,inf);
printf("%d",ans);
return 0;
}