[BZOJ 2768] 冠军调查
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2768
Solution:
一道比较基础的最大流的题目
一般看到将点分为两类的题目就要往网络流方向想吧
建图:
源点向每个初始立场为1的人连权值为1的边。
每个初始立场为0的人向汇点连权值为1的边。
好朋友之间互相连权值为1的边。
最小割即是答案。
要满足要求且总和最小,就不能让任何一对(1,0)关系成立,这便对应着最小割模型
割与源/汇点的边对应“说谎”,割二分图内部的边对应“立场不同”
Code:
//by NewErA #include <bits/stdc++.h> using namespace std; #define FF first #define SS second #define PB push_back #define MP make_pair #define bged(v) (v).begin(),(v).end() #define foreach(it,s) for(__typeof((s).begin()) it=(s).begin();it!=(s).end();it++) typedef long long ll; typedef pair<int,int> P; typedef pair<pair<int,int>,int> PP; const int INF=1<<27; const int MOD=1e9+7; //My IO system struct fastio { char s[100000]; int it,len; fastio(){it=len=0;} inline char get() { if(it<len)return s[it++];it=0; len=fread(s,1,100000,stdin); if(len==0)return EOF;else return s[it++]; } bool notend() { char c=get(); while(c==' '||c=='\n')c=get(); if(it>0)it--; return c!=EOF; } }_buff; #define Read1(x) x=getnum() #define Read2(x,y) Read1(x),Read1(y) #define Read3(x,y,z) Read2(x,y),Read1(z) #define Write1(x) putnum(x),putchar('\n') #define Write2(x,y) Write1(x),Write1(y) #define Write3(x,y,z) Write2(x,y),Write1(z) inline ll getnum() { ll r=0;bool ng=0;char c;c=_buff.get(); while(c!='-'&&(c<'0'||c>'9'))c=_buff.get(); if(c=='-')ng=1,c=_buff.get(); while(c>='0'&&c<='9')r=r*10+c-'0',c=_buff.get(); return ng?-r:r; } template<class T> inline void putnum(T x) { if(x<0)putchar('-'),x=-x; register short a[20]={},sz=0; while(x)a[sz++]=x%10,x/=10; if(sz==0)putchar('0'); for(int i=sz-1;i>=0;i--)putchar('0'+a[i]); } const int MAXN=500; int n,m,s,t,level[MAXN],iter[MAXN],dat[MAXN]; struct edge { int to,cap,rev; }; vector<edge> a[MAXN]; void add_edge(int to,int from,int cap) { a[to].push_back(edge{from,cap,a[from].size()}); a[from].push_back(edge{to,cap,a[to].size()-1}); } void bfs() { memset(level,-1,sizeof(level)); queue<int> Q;Q.push(s);level[s]=0; while(!Q.empty()) { int cur=Q.front();Q.pop(); for(int i=0;i<a[cur].size();i++) { edge e=a[cur][i]; if(e.cap && level[e.to]==-1) { level[e.to]=level[cur]+1; Q.push(e.to); } } } } int dfs(int v,int f) { if(v==t) return f; int ret=0; for(int &i=iter[v];i<a[v].size();i++) { edge &e=a[v][i]; if(level[e.to]==level[v]+1 && e.cap) { int d=dfs(e.to,min(f,e.cap)); f-=d;ret+=d; e.cap-=d;a[e.to][e.rev].cap+=d; if(!f) break; } } return ret; } int main() { Read2(n,m);s=n+1,t=s+1; for(int i=1;i<=n;i++) { Read1(dat[i]); if(dat[i]) add_edge(i,t,1); else add_edge(s,i,1); } for(int i=1;i<=m;i++) { int x,y;Read2(x,y); if(dat[x]!=dat[y]) add_edge(x,y,1); } ll res=0; while(true) { memset(iter,0,sizeof(iter)); bfs();int f=0; if(level[t]<0) break; res+=dfs(s,INF); } cout << res; return 0; }
Review:
很多时候碰到这样类似的二元关系就要往网络流方向想
割的边容量即为计入答案的数值