20211011二分图匹配+判定

20211019 今天打模板发现自己的代码居然打错了,太丢脸了~~~

怪不得wa了一个小时

 

----------------分割线--------------------

今天又是摸鱼的一天,就复习了一下数据结构,然后树剖板子打炸了,线段树2调疯了,tarjan也搞没了。

还有就是学了一下二分图,之前假期发了学案懒得看,今天就跑过去听,感觉还不错。

1.二分图是什么:

二分图又称作二部图,是图论中的一种。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

简单来说,就是能把定点分成两部分,任意两点间有且只有一条路径。

至于二分图的判定,我们用深度搜索染色来实现。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,color[205];
 5 vector<int> node[205];//领接表存图
 6 
 7 bool dfs(int v,int c){//搜索染色
 8     color[v]=c;
 9     for(int i=0;i<node[v].size();i++){
10         if(color[node[v][i]]==c){//相连的点颜色必须不同
11             return 0;
12         }else if(color[node[v][i]]==0&&!dfs(node[v][i],-c)){//还未染色切染了色也没有问题
13             return 0;
14         }
15     }
16     return 1;
17 }
18 int main(){
19     int u,v;
20     cin>>n>>m;
21     for(int i=0;i<m;i++){
22         cin>>u>>v;
23         node[u].push_back(v);
24         node[v].push_back(u);
25     }
26     
27     for(int i=0;i<n;i++){
28         if(color[i]==0){//从每一个点开始
29             if(!dfs(i,1)){
30                 cout<<"NO"<<endl;
31                 return 0;
32             }
33         }
34     }
35     cout<<"YES"<<endl;
36     
37     
38     return 0;
39 }

例题:关押罪犯https://www.luogu.com.cn/problem/P1525

思路:二分答案+染色搜索判定

先排序按照暴力事件的大小升序排列,然后二分一个答案,如果MID满足条件那么大于mid的都可以,接下来就向左半边二分。

我们每找到一个mid的值就用一个check函数判断是否合法。判断方式就是,把大于mid的边存入领接表,再用染色判断大于他的边能否形成一个二分图。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int N=20010;
  5 const int M=100010;
  6 int n,m,color[N];
  7 bool flag;
  8 vector<int> e[N];
  9 struct edges{
 10     int x,y,v;
 11 }a[M]; 
 12 
 13 bool cmp(edges a,edges b){
 14     return a.v<b.v;
 15 }
 16 
 17 //void dfs(int u,int c){
 18 //    color[u]=c;
 19 //    for(int i=0;i<e[i].size();i++){
 20 //        int v=e[u][i];
 21 //         if(!color[v]){
 22 //            dfs(v,-c);
 23 //        }else 
 24 //        if(color[v]==c){
 25 //            flag=0;
 26 //        }
 27 //    }
 28 //}
 29 void dfs(int u, int c)  //染色  
 30 { 
 31     color[u]=c; 
 32     for(int i=0;i<e[u].size();i++) //枚举从u出
 33   { 
 34         int v=e[u][i];             //v是u的相邻
 35         if(!color[v]) dfs(v,-c);             //继续染色  
 36         else if(color[v]==c) flag=false;  //颜色
 37     } 
 38 } 
 39  
 40 
 41 //bool check(int pos){
 42 //    for(int i=1;i<=n;i++) e[i].clear();
 43 //    for(int i=pos+1;i<=m;i++){
 44 //        e[a[i].x].push_back(a[i].y);
 45 //        e[a[i].y].push_back(a[i].x);
 46 //    }
 47 //    flag=true;
 48 //    memset(color,0,sizeof(color));
 49 //    for(int i=1;i<=n;i++){
 50 //        if(!color[i]){
 51 //            dfs(i,1);
 52 //            if(!flag) return false;
 53 //        }
 54 //    } 
 55 //    return true;
 56 //}
 57 
 58 bool check(int pos)  //判断是否合法:能构成
 59 { 
 60     for(int i=1;i<=n;i++) e[i].clear();  //
 61     for(int i=pos+1;i<=m;i++)            //
 62   { 
 63         e[a[i].x].push_back(a[i].y); 
 64         e[a[i].y].push_back(a[i].x); 
 65     } 
 66     flag=true; 
 67     memset(color,0,sizeof color); 
 68     for(int i=1;i<=n;i++)                //
 69         if(!color[i]) 
 70     { 
 71             dfs(i,1); 
 72             if(!flag) return false; 
 73         } 
 74     return true; 
 75 } 
 76 int main()
 77 {
 78     cin>>n>>m;
 79     for(int i=1;i<=m;i++){
 80         cin>>a[i].x>>a[i].y>>a[i].v;
 81     }
 82     sort(a+1,a+m+1,cmp);
 83 
 84     int l=0;
 85     int r=m;
 86     int mid;
 87 //    while(l<r){
 88 //         mid=(l+r)>>1;
 89 //        if(check(mid)){
 90 //            r=mid;
 91 //            cout<<r<<' '<<123<<endl;
 92 //        }else l=mid+1,cout<<l<<' '<<321<<endl;
 93 //    }
 94     while(l<r) 
 95   { 
 96         mid=(l+r)>>1; 
 97         if(check(mid)) 
 98       r=mid;        
 99         else 
100       l=mid+1;      
101     } 
102     if(m==1){
103         cout<<0<<endl;
104     } else{
105     
106         cout<<a[l].v<<endl;
107     }
108     return 0;
109 }

 咕咕咕,晚自习还有十分钟下课,拼手速的时刻到了:

好的上面讲完了二分图的判定,我们再来讲二分图的最优匹配:

一般来说,二分图的匹配我们用网络流或者匈牙利算法来做,但是单纯的二分图匹配的话,匈牙利算法虽然在时间复杂度上处于劣势但是编程难度小;

至于网络流吗?蒟蒻暑假也学过,但是忘完了,也难写,一个广搜加一个深搜,还有玄学弧优化和多路增广:

接下来就是匈牙利的模板了:

就是男女匹配:

每一个女生有多个喜欢的男生(两个集合之间的连边),现在求可以撮合的最多情侣数量{单身狗微笑}

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int match[505];
 5 int used[505];
 6 int k,m,n,x,y;
 7 vector<int> e[1005];//领接表~~
 8 
 9 bool Dfs(int x)
10 {
11     for(int i=0;i<e[x].size();i++){
12         if(!used[e[x][i]]){//男生在 “”当前“” 状态下没有被匹配
13             used[e[x][i]]=1;
14             if(match[e[x][i]]==0||Dfs(match[e[x][i]])){//男生一直没有“女”朋友 或 该男生之前匹配的女士可以换一个男生
15                 match[e[x][i]]=x;//男生换一个
16                 return 1;
17             }
18         }
19     }
20     return 0;
21 }
22 int main()
23 {
24     while(scanf("%d",&k)!=EOF&&k){
25         cin>>m>>n;
26         for(int i=1;i<=k;i++){
27             e[i].clear();
28         }
29         memset(match,0,sizeof(match));
30         for(int i=1;i<=k;i++){
31             cin>>x>>y;
32             e[x].push_back(y);//连边
33         }
34         int sum=0;
35         for(int i=1;i<=m;i++){//分别从每一个女生开始
36             memset(used,0,sizeof(used));//清空
37             if(Dfs(i)) sum++;//在不影响其他人的情况下成功了
38         }
39         cout<<sum<<endl;
40     }
41     return 0;
42 }

马上来一道有趣的例题,先自己看哟~~~

 http://poj.org/problem?id=2536

不要抄题解呀

题目描述】
草原某片区域上有 N 个地鼠正在地面寻食,附近有 M 个地鼠洞,地鼠和地鼠洞的当前位置用坐标(x,y)表示。每个洞只能容纳一个地鼠。

一只老鹰正飞向这里,如果地鼠在 S 秒内没有进入地鼠洞,则会被老鹰吃掉。所有地鼠都以同一速度 V 进行逃生。请你帮地鼠家族设计一个优秀的逃生策略,使得损失的地鼠最少。

【输入格式】

输入包含多组数据。
每组数据的第一行包含四个不超过100的正整数:N,M,S,V。
接下来的n行,每行两个实数,表示一个地鼠的坐标;
接下来M行,每行两个实数,表示一个地鼠洞的坐标。
所有的距离单位是“米”,所有的时间单位是“秒”,所有的速度单位是“米/秒”。

【输出格式】
对每组数据输出一行,一个整数,表示至少要被老鹰吃掉的地鼠的数量。

【输入样例】
2 2 5 10
1.0 1.0
2.0 2.0
100.0 100.0
20.0 20.0


【输出样例】

1

板子题了?

 

在每一只地鼠he他能跑到的洞之间连一条边,在该图上用匈牙利

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,s,v;
 4 struct node{
 5     double x,y;
 6 }mouse[110],hole[110];
 7 double work(int i,int j){
 8     return sqrt((mouse[i].x-hole[j].x)*(mouse[i].x-hole[j].x)+(mouse[i].y-hole[j].y)*(mouse[i].y-hole[j].y)); //计算距离
 9 }
10 vector<int> e[200];
11 int used[110],match[110];
12 
13 bool Dfs(int x){
14     for(int i=0;i<e[x].size();i++){
15         if(!used[e[x][i]]){
16             used[e[x][i]]=1;
17             if(match[e[x][i]]==0||Dfs(match[e[x][i]])){
18                 match[e[x][i]]=x;
19                 return 1;
20             }
21         }
22     }
23     return 0;
24 }
25 int main()
26 {
27     cin>>n>>m>>s>>v;
28     for(int i=1;i<=n;i++){
29         cin>>mouse[i].x>>mouse[i].y;
30     }
31     for(int i=1;i<=m;i++){
32         cin>>hole[i].x>>hole[i].y;
33     }
34     for(int i=1;i<=n;i++){
35         for(int j=1;j<=m;j++){
36             int len=work(i,j);
37             if(len<s*v){
38                 e[i].push_back(j);//连边
39             }
40         }
41     }
42     int sum=0;
43     for(int i=1;i<=n;i++){
44         memset(used,0,sizeof(used));
45         if(Dfs(i)) sum++;
46     }
47     cout<<n-sum<<endl;//输出被吃掉的个数
48     return 0;
49 }

好了,这篇博客咕了一周终于搞完了,累死竞赛狗了

马上CSP了,各位rp++

拜拜(^_^)

开始颓废了

posted @ 2021-10-11 22:01  SSZX_loser_lcy  阅读(63)  评论(0编辑  收藏  举报