二分图??(自用,勿看)

注意:这是一篇个人学习笔记,如果有人因为某些原因点了进来并且要看一下,请一定谨慎地阅读,因为可能存在各种奇怪的错误,如果有人发现错误请指出谢谢!


只能先背着了...

资料:https://www.cnblogs.com/jianglangcaijin/p/6035945.html

二分图的最小顶点覆盖
定义:假如选了一个点就相当于覆盖了以它为端点的所有边。最小顶点覆盖就是选择最少的点来覆盖所有的边。
方法:最小顶点覆盖=最大匹配

二分图的最大独立集
定义:选出一些顶点使得这些顶点两两不相邻,则这些点构成的集合称为独立集。找出一个包含顶点数最多的独立集称为最大独立集。
方法:最大独立集=所有顶点数-最小顶点覆盖

二分图的最大团
定义:对于一般图来说,团是一个顶点集合,且由该顶点集合诱导的子图是一个完全图,简单说,就是选出一些顶点,这些顶点两两之间都有边。最大团就是使得选出的这个顶点集合最大。对于二分图来说,我们默认为左边的所有点之间都有边,右边的所有顶点之间都有边。那么,实际上,我们是要在左边找到一个顶点子集X,在右边找到一个顶点子集Y,使得X中每个顶点和Y中每个顶点之间都有边。
方法:最大团=补图的最大独立集。补图的定义是:对于二分图中左边一点x和右边一点y,若x和y之间有边,那么在补图中没有,否则有。

资料:https://blog.csdn.net/flynn_curry/article/details/52966283

资料:https://blog.csdn.net/wall_f/article/details/8187144

二分图的最小边覆盖
定义:假如选了一条边就相当于覆盖了它的两个端点。最小边覆盖就是选择最少的边来覆盖所有的顶点。
方法:最小边覆盖=最大独立集=所有顶点数-最大匹配


二分图最大匹配

匈牙利算法资料:https://www.cnblogs.com/wangjunyan/p/5563154.html

当然也可以网络流直接跑,对于给定二分图,S向一边的点连边,另一边的点向T连边,跑S到T最大流即可;复杂度的话,用dinic好像可以证sqrt(n)*m


资料(一些证明?):https://blog.csdn.net/u013043514/article/details/48206577

二分图的最小路径覆盖

定义:用最少的不相交路径覆盖所有顶点。
定理:把原图中的每个点V拆成Vx和Vy,如果有一条有向边A−>B,那么就加边(Ax,By)。这样就得到了一个二分图,最小路径覆盖=原图的节点数-新图最大匹配。

不需要输出方案:http://210.33.19.103/contest/877/problem/3

需要输出方案:https://www.luogu.org/problemnew/show/P2764

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<queue>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13 typedef pair<int,int> pii;
 14 namespace F
 15 {
 16 
 17 struct E
 18 {
 19     int to,nxt,from,cap,flow;
 20 }e[2001000];
 21 int f1[10100],ne=1;
 22 int S,T,n;
 23 int d[10100];
 24 bool bfs()
 25 {
 26     int k,u;
 27     memset(d,0,sizeof(int)*(n+1));
 28     queue<int> q;
 29     q.push(S);d[S]=1;
 30     while(!q.empty())
 31     {
 32         u=q.front();q.pop();
 33         for(k=f1[u];k;k=e[k].nxt)
 34             if(!d[e[k].to]&&e[k].cap>e[k].flow)
 35             {
 36                 d[e[k].to]=d[u]+1;
 37                 if(e[k].to==T)    return 1;
 38                 q.push(e[k].to);
 39             }
 40     }
 41     return 0;
 42 }
 43 int cur[10100];
 44 int dfs(int u,int x)
 45 {
 46     if(u==T||x==0)    return x;
 47     int flow=0,f;
 48     for(int &k=cur[u];k;k=e[k].nxt)
 49         if(e[k].cap>e[k].flow&&d[e[k].to]==d[u]+1)
 50         {
 51             f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
 52             e[k].flow+=f;e[k^1].flow-=f;flow+=f;
 53             if(flow==x)    return flow;
 54         }
 55     return flow;
 56 }
 57 int solve()
 58 {
 59     int flow=0;
 60     while(bfs())
 61     {
 62         memcpy(cur,f1,sizeof(int)*(n+1));
 63         flow+=dfs(S,0x3f3f3f3f);
 64     }
 65     return flow;
 66 }
 67 
 68 void me(int a,int b,int c)
 69 {
 70     e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
 71     e[ne].from=a;e[ne].cap=c;
 72     e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
 73     e[ne].from=b;e[ne].cap=0;
 74 }
 75 
 76 }
 77 inline int read()
 78 {
 79     int x = 0, f = 1;
 80     char ch = getchar();
 81     while (ch<'0' || ch>'9') { if (ch == '-') f = -1; ch = getchar(); }
 82     while ('0' <= ch && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
 83     return x * f;
 84 }
 85 int pre[100100];
 86 int n,m;
 87 bool vis[100100];
 88 void work()
 89 {
 90     using namespace F;
 91     int i;
 92     for(i=2;i<=ne;i+=2)
 93     {
 94         if(e[i].flow==1&&e[i].from>=1&&e[i].from<=::n&&e[i].to>=::n+1&&e[i].to<=2*::n)
 95         {
 96             //printf("t%d %d\n",e[i].from,e[i].to);
 97             pre[e[i].to-::n]=e[i].from;
 98             vis[e[i].from]=1;
 99         }
100     }
101 }
102 void out(int p)
103 {
104     vis[p]=1;
105     if(pre[p])    out(pre[p]);
106     printf("%d ",p);
107 }
108 int main()
109 {
110     int i,a,b;
111     scanf("%d%d",&n,&m);
112     {
113         using F::me;
114         for(i=1;i<=m;i++)
115         {
116             scanf("%d%d",&a,&b);
117             me(a,b+n,1);
118         }
119         F::S=n+n+1;F::T=n+n+2;F::n=n+n+2;
120         for(i=1;i<=n;i++)    me(F::S,i,1);
121         for(i=1;i<=n;i++)    me(i+n,F::T,1);
122     }
123     int an=n-F::solve();
124     work();
125     for(i=1;i<=n;i++)
126     {
127         if(!vis[i])
128         {
129             out(i);
130             puts("");
131         }
132     }
133     printf("%d",an);
134     return 0;
135 }
View Code

二分图最大权完美匹配

板子:https://www.luogu.org/problemnew/show/P4014

km算法先放着了..

可以按二分图最大匹配的方法建网络流的图,然后新图中,每条原二分图中的边对应的边给上对应费用的相反数,其他边给费用0。跑最小费用最大流,如果最大流没有等于点数就是没有完美匹配,否则有。最后的答案就是最小费用的相反数;输出方案跟二分图最大匹配是类似的

二分图最大权任意(不一定要完美)匹配

km的板子(网络流A不了):http://uoj.ac/problem/80

km算法先放着了..

网络流的板子:http://210.33.19.103/problem/2155

网络流的做法,就是用完美匹配的做法,但是每次增广完都统计一下当前的费用,取所有费用的最小值的相反数作为最终答案(当然更新费用时可能也要记录一下方案)

显然每次增广只可能恰好增加1的流量,所以是对的

这个的复杂度稍微比费用流低一点,因为总流量最多只有原图中点数级别,每次增广最少增加1的流量,增广次数就是O(n)的

用spfa费用流复杂度是n*n*m

  1 %:pragma GCC optimize(3)
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<vector>
  6 #include<queue>
  7 using namespace std;
  8 #define fi first
  9 #define se second
 10 #define mp make_pair
 11 #define pb push_back
 12 typedef long long ll;
 13 typedef unsigned long long ull;
 14 typedef pair<int,int> pii;
 15 void work();
 16 namespace F
 17 {
 18 
 19 struct E
 20 {
 21     int to,nxt,d,from,cap,flow;
 22 }e[401000];
 23 int f1[5010],ne=1;
 24 int S,T,n;
 25 bool inq[5010];
 26 ll d[5010];int pre[5010],minn[5010];
 27 int flow;ll cost,co2;
 28 void solve()
 29 {
 30     int k,u;
 31     flow=cost=co2=0;
 32     while(1)
 33     {
 34         memset(d,0x3f,sizeof(ll)*(n+1));
 35         memset(inq,0,sizeof(bool)*(n+1));
 36         queue<int> q;
 37         q.push(S);d[S]=0;pre[S]=0;inq[S]=1;minn[S]=0x3f3f3f3f;
 38         while(!q.empty())
 39         {
 40             u=q.front();q.pop();
 41             inq[u]=0;
 42             //if(u==T)    break;
 43             for(k=f1[u];k;k=e[k].nxt)
 44                 if(e[k].cap>e[k].flow&&d[u]+e[k].d<d[e[k].to])
 45                 {
 46                     d[e[k].to]=d[u]+e[k].d;
 47                     pre[e[k].to]=k;
 48                     minn[e[k].to]=min(minn[u],e[k].cap-e[k].flow);
 49                     if(!inq[e[k].to])
 50                     {
 51                         inq[e[k].to]=1;
 52                         q.push(e[k].to);
 53                     }
 54                 }
 55         }
 56         if(d[T]==0x3f3f3f3f3f3f3f3f)    break;
 57         flow+=minn[T];cost+=d[T]*minn[T];
 58         for(k=pre[T];k;k=pre[e[k].from])
 59         {
 60             e[k].flow+=minn[T];e[k^1].flow-=minn[T];
 61         }
 62         if(cost<co2)
 63         {
 64             co2=cost;
 65             work();
 66         }
 67     }
 68 }
 69 void me(int a,int b,int c,int d)
 70 {
 71     e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].from=a;
 72     e[ne].cap=c;e[ne].d=d;
 73     e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].from=b;
 74     e[ne].cap=0;e[ne].d=-d;
 75 }
 76 
 77 }
 78 int an[5010];
 79 int n1,n2,m;
 80 void work()
 81 {
 82     using namespace F;
 83     int i,k;
 84     for(i=1;i<=n1;i++)
 85     {
 86         for(k=f1[i];k;k=e[k].nxt)
 87             if(n1+1<=e[k].to&&e[k].to<=n1+n2&&e[k].flow==1)
 88             {
 89                 an[i]=e[k].to-n1;
 90                 //printf("%d ",e[k].to-n1);
 91                 goto xxx;
 92             }
 93         an[i]=0;//printf("%d ",0);
 94         xxx:;
 95     }
 96 }
 97 int main()
 98 {
 99     int i,a,b,c;
100     scanf("%d%d%d",&n1,&n2,&m);
101     for(i=1;i<=m;i++)
102     {
103         scanf("%d%d%d",&a,&b,&c);
104         F::me(a,b+n1,1,-c);
105     }
106     F::n=n1+n2+2;F::S=n1+n2+1;F::T=n1+n2+2;
107     for(i=1;i<=n1;i++)    F::me(F::S,i,1,0);
108     for(i=1;i<=n2;i++)    F::me(i+n1,F::T,1,0);
109     F::solve();
110     printf("%lld\n",-F::co2);
111     for(i=1;i<=n1;i++)    printf("%d ",an[i]);
112     return 0;
113 }
View Code

用原始对偶复杂的是n*m*log

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<queue>
  6 #include<ext/pb_ds/assoc_container.hpp>
  7 #include<ext/pb_ds/priority_queue.hpp>
  8 using namespace std;
  9 #define fi first
 10 #define se second
 11 #define mp make_pair
 12 #define pb push_back
 13 typedef long long ll;
 14 typedef unsigned long long ull;
 15 typedef pair<ll,int> pli;
 16 void work();
 17 namespace F
 18 {
 19 
 20 struct E
 21 {
 22     int to,nxt,d,from,cap,flow;
 23 }e[2010000];
 24 int f1[1010],ne=1;
 25 int S,T,n;
 26 bool inq[1010],*vis=inq;
 27 ll d[1010];
 28 ll h[1010];
 29 int flow;ll cost,co2;
 30 typedef __gnu_pbds::priority_queue<pli,greater<pli> > pq;
 31 pq::point_iterator it[1010];
 32 bool spfa()
 33 {
 34     int u,k,k1;
 35     memset(d,0x3f,sizeof(d[0])*(n+1));
 36     memset(inq,0,sizeof(inq[0])*(n+1));
 37     queue<int> q;
 38     q.push(T);d[T]=0;inq[T]=1;
 39     while(!q.empty())
 40     {
 41         u=q.front();q.pop();
 42         inq[u]=0;
 43         for(k1=f1[u];k1;k1=e[k1].nxt)
 44         {
 45             k=k1^1;
 46             if(e[k].cap>e[k].flow&&d[u]+e[k].d<d[e[k].from])
 47             {
 48                 d[e[k].from]=d[u]+e[k].d;
 49                 if(!inq[e[k].from])
 50                 {
 51                     inq[e[k].from]=1;
 52                     q.push(e[k].from);
 53                 }
 54             }
 55         }
 56     }
 57     return d[S]!=0x3f3f3f3f3f3f3f3f;
 58 }
 59 bool dij()
 60 {
 61     int i,u,k,k1;pli t;
 62     memset(d,0x3f,sizeof(d[0])*(n+1));
 63     memset(vis,0,sizeof(vis[0])*(n+1));
 64     pq q;
 65     for(i=1;i<=n;i++)    it[i]=q.end();
 66     it[T]=q.push(mp(0,T));d[T]=0;
 67     while(!q.empty())
 68     {
 69         t=q.top();q.pop();
 70         u=t.se;
 71         if(vis[u])    continue;
 72         vis[u]=1;
 73         for(k1=f1[u];k1;k1=e[k1].nxt)
 74         {
 75             k=k1^1;
 76             if(e[k].cap>e[k].flow&&d[u]+e[k].d+h[u]-h[e[k].from]<d[e[k].from])
 77             {
 78                 d[e[k].from]=d[u]+e[k].d+h[u]-h[e[k].from];
 79                 if(it[e[k].from]!=q.end())    q.modify(it[e[k].from],mp(d[e[k].from],e[k].from));
 80                 else    it[e[k].from]=q.push(mp(d[e[k].from],e[k].from));
 81             }
 82         }
 83     }
 84     return d[S]!=0x3f3f3f3f3f3f3f3f;
 85 }
 86 void update()
 87 {
 88     for(int i=1;i<=n;i++)    h[i]+=d[i];
 89 }
 90 int dfs(int u,int x)
 91 {
 92     if(u==T||x==0)    return x;
 93     int flow=0,f;
 94     vis[u]=1;
 95     for(int k=f1[u];k;k=e[k].nxt)
 96         if(!vis[e[k].to]&&e[k].cap>e[k].flow&&h[e[k].to]==h[u]-e[k].d)
 97         {
 98             f=dfs(e[k].to,min(x-flow,e[k].cap-e[k].flow));
 99             e[k].flow+=f;e[k^1].flow-=f;flow+=f;
100             if(flow==x)    return flow;
101         }
102     return flow;
103 }
104 void augment()
105 {
106     int f;
107     while(1)
108     {
109         memset(vis,0,sizeof(vis[0])*(n+1));
110         f=dfs(S,0x3f3f3f3f);
111         if(!f)    break;
112         flow+=f;cost+=f*h[S];
113         if(cost<co2)
114         {
115             co2=cost;
116             work();
117         }
118     }
119 }
120 void solve()
121 {
122     flow=cost=0;
123     memset(h,0,sizeof(h[0])*(n+1));
124     if(!spfa())    return;
125     do
126     {
127         update();
128         augment();
129     }while(dij());
130 }
131 void me(int a,int b,int c,int d)
132 {
133     e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].from=a;
134     e[ne].cap=c;e[ne].d=d;
135     e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].from=b;
136     e[ne].cap=0;e[ne].d=-d;
137 }
138 
139 }
140 
141 int an[1010];
142 int n1,n2,m;
143 void work()
144 {
145     using namespace F;
146     int i,k;
147     for(i=1;i<=n1;i++)
148     {
149         for(k=f1[i];k;k=e[k].nxt)
150             if(n1+1<=e[k].to&&e[k].to<=n1+n2&&e[k].flow==1)
151             {
152                 an[i]=e[k].to-n1;
153                 goto xxx;
154             }
155         an[i]=0;
156         xxx:;
157     }
158 }
159 int main()
160 {
161     int i,a,b,c;
162     scanf("%d%d%d",&n1,&n2,&m);
163     for(i=1;i<=m;i++)
164     {
165         scanf("%d%d%d",&a,&b,&c);
166         F::me(a,b+n1,1,-c);
167     }
168     F::n=n1+n2+2;F::S=n1+n2+1;F::T=n1+n2+2;
169     for(i=1;i<=n1;i++)    F::me(F::S,i,1,0);
170     for(i=1;i<=n2;i++)    F::me(i+n1,F::T,1,0);
171     F::solve();
172     printf("%lld\n",-F::co2);
173     //for(i=1;i<=n1;i++)    printf("%d ",an[i]);
174     return 0;
175 }
View Code

 

posted @ 2018-09-10 16:43  hehe_54321  阅读(251)  评论(0编辑  收藏  举报
AmazingCounters.com