http://www.lydsy.com/JudgeOnline/problem.php?id=1934
一开始我想到了这是求最小割,但是我认为这题二分图可做,将1的放在左边,0的放在右边,然后朋友连边,如果有冲突就相当于有1条x-y的边,求最小割也就是最大匹配即可。。可是不知道为什么就错了。
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%d", a) #define dbg(x) cout << #x << " = " << x << endl #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; } inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=310, M=N*N/2, oo=~0u>>1; int ihead[N], cnt=1, n, m, ly[N], x[N], cx, y[N], cy, vis[N]; struct ED { int from, to, cap, next; } e[M]; inline void add(const int &u, const int &v) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; } const bool ifind(const int &x) { vis[x]=1; int y; for(int i=ihead[x]; i; i=e[i].next) if(!vis[y=e[i].to]) { vis[y]=1; if(!ly[y] || ifind(ly[y])) { ly[y]=x; return true; } } return false; } int main() { read(n); read(m); int t, ans=0; for1(i, 1, n) { read(t); if(t) x[++cx]=i; else y[++cy]=i; } rep(i, m) add(getint(), getint()); for1(i, 1, cx) { CC(vis, 0); if(ifind(x[i])) ++ans; } print(ans); return 0; }
后来无奈看了题解,恩,也是差不多。
首先也是二分图,将s连到1的点,点为0连到t,容量均为1(1的点集我设x,0的点集我设为y)
然后连兄弟边,容量均为1(双向)
然后求最小割就是答案
为什么呢。。
因为我们设s就代表了1,t代表了0,而一个割C(s, t)就代表了一个解决冲突的方案,如果某个x集里的点a现在被割分到了t,那么它与s的边一定断掉(代表他自己违背自己),与x集或y集的其它分到s的点的边也一定断掉(代表了它解决冲突的方案)
所以最小割就代表了最优方案。
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%d", a) #define dbg(x) cout << #x << " = " << x << endl #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; } inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=320, M=N*N*2, oo=~0u>>1; int ihead[N], cnt=1, cur[N], gap[N], d[N], p[N], n, m; struct ED { int from, to, cap, next; } e[M]; inline void add(const int &u, const int &v, const int &w) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].from=u; e[cnt].cap=w; e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].from=v; e[cnt].cap=0; } int isap(const int &s, const int &t, const int &n) { for1(i, 0, n) cur[i]=ihead[i]; int ret=0, i, f, u=s; gap[0]=n; while(d[s]<n) { for(i=cur[u]; i; i=e[i].next) if(e[i].cap && d[u]==d[e[i].to]+1) break; if(i) { p[e[i].to]=cur[u]=i; u=e[i].to; if(u==t) { for(f=oo; u!=s; u=e[p[u]].from) f=min(f, e[p[u]].cap); for(u=t; u!=s; u=e[p[u]].from) e[p[u]].cap-=f, e[p[u]^1].cap+=f; ret+=f; } } else { if(! (--gap[d[u]]) ) break; d[u]=n; cur[u]=ihead[u]; for(i=ihead[u]; i; i=e[i].next) if(e[i].cap && d[u]>d[e[i].to]+1) d[u]=d[e[i].to]+1; ++gap[d[u]]; if(u!=s) u=e[p[u]].from; } } return ret; } int main() { read(n); read(m); int s=n+10, t=s+1, tp; for1(i, 1, n) { read(tp); if(tp) add(s, i, 1); else add(i, t, 1); } for1(i, 1, m) { int t1=getint(), t2=getint(); add(t1, t2, 1); add(t2, t1, 1); } print(isap(s, t, t+1)); return 0; }
在第一个例子中,所有小朋友都投赞成票就能得到最优解