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


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


    只能先背着了...

    资料: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
    ",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
    ",-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
    ",-F::co2);
    173     //for(i=1;i<=n1;i++)    printf("%d ",an[i]);
    174     return 0;
    175 }
    View Code
  • 相关阅读:
    Well, that was fun! An adventure in WCF, SSL, and Host Headers (转)
    算法还重要吗?
    Silverlight测试——利用Ranorex实现数据驱动测试
    MSSQl分布式查询
    Silverlight 4 CHM中文离线文档已提供下载
    快速打包你的应用程序——Inno Setup
    IE 9 Beta 测试Bug
    IE 9 Bate 泄露版
    Windows PowerShell初体验——.NET对象支持
    多样化实现Windows Phone 7本地数据库访问<2>
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9620798.html
Copyright © 2020-2023  润新知