P2057 [SHOI2007]善意的投票

时间:2023-03-09 05:08:03
P2057 [SHOI2007]善意的投票

思路

简单的最小割模型

最小割的模型就是选出一些边,把点集划分成S和T两个部分,使得代价最小

到这题上就是板子了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int MAXN = 1000;
const int INF = 0x3f3f3f3;
int n,m;
struct Edge{
int u,v,cap,flow;
};
vector<Edge> edges;
vector<int> G[MAXN];
void addedge(int u,int v,int cap){
edges.push_back((Edge){u,v,cap,0});
edges.push_back((Edge){v,u,0,0});
int cnt=edges.size();
G[u].push_back(cnt-2);
G[v].push_back(cnt-1);
}
int cur[MAXN],vis[MAXN],dep[MAXN],s,t;
int dfs(int x,int a){
if(x==t||a==0)
return a;
int flow=0,f=0;
for(int &i=cur[x];i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(dep[e.v]==dep[x]+1&&(f=dfs(e.v,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[G[x][i]^1].flow-=f;
a-=f;
flow+=f;
if(!a)
break;
}
}
return flow;
}
queue<int> q;
bool bfs(void){
memset(vis,0,sizeof(vis));
q.push(s);
vis[s]=true;
dep[s]=0;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<G[x].size();i++){
Edge &e = edges[G[x][i]];
if(e.cap>e.flow&&(!vis[e.v])){
vis[e.v]=true;
dep[e.v]=dep[x]+1;
q.push(e.v);
}
}
}
return vis[t];
}
int dinic(void){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
int main(){
s=MAXN-2;
t=MAXN-3;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(x)
addedge(s,i,1);
else
addedge(i,t,1);
}
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
addedge(a,b,1);
addedge(b,a,1);
}
printf("%d\n",dinic());
return 0;
}