题目链接:
https://www.luogu.org/problemnew/show/P2057
分析:
由0和1的选择我们直觉的想到0与S一堆,1与T一堆。
但是发现,刚开始的主意并不一定是最终的结果。
于是用源点S表示最终选择0的集合。
汇点T表示最终选择1的集合。
如果一个人P选择了0,那么S−>PS->PS−>P连一条流量为1的边,然后P−>TP->TP−>T连一条流量为0的边。
反之如果P选择了1,那么S−>PS->PS−>P连一条流量为0的边,然后P−>TP->TP−>T连一条流量为1的边。
最后把所有朋友对之间连流量为1的双向边(关系相互)
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#define inf 0x7fffffff
using namespace std;
int s,t,ans;
int d[505];
struct edge
{
int to,val,rev;
edge(int _to,int _val,int _rev)
{
to=_to;
val=_val;
rev=_rev;
}
};
vector<edge>e[505];
void add(int x,int y,int w)
{
e[x].push_back(edge(y,w,e[y].size()));
e[y].push_back(edge(x,0,e[x].size()-1));
}
bool bfs()
{
queue<int>q;
memset(d,-1,sizeof(d));
d[s]=0;
q.push(s);
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
if(d[y]==-1&&e[x][i].val)
{
q.push(y);
d[y]=d[x]+1;
}
}
}
if(d[t]==-1)return 0;
return 1;
}
int dfs(int x,int low)
{
if(x==t || low==0)
return low;
int totflow=0;
for(int i=0;i<e[x].size();i++)
{
int y=e[x][i].to;
int rev=e[x][i].rev;
if(d[y]==d[x]+1 && e[x][i].val)
{
int a=dfs(y,min(low,e[x][i].val));
e[x][i].val-=a;
e[y][rev].val+=a;
low-=a;
totflow+=a;
if(low==0)
return totflow;
}
}
if(low!=0)
d[x]=-1;
return totflow;
}
void dinic()
{
while(bfs())
{
//printf("%d\n",ans);
ans+=dfs(s,inf);
}
}
int main()
{
int n,m,x,y,o;
scanf("%d%d",&n,&m);
s=0;t=500;
for(int i=1;i<=n;i++)
{
scanf("%d",&o);
if(o==0)
{
add(s,i,1);//add(i,t,0);
}
else
{
//add(s,i,0);
add(i,t,1);
}
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y,1);add(y,x,1);
}
dinic();
printf("%d\n",ans);
return 0;
}