luoguP2526_[SHOI2001]小狗散步_二分图匹配

题意:

Grant喜欢带着他的小狗Pandog散步。Grant以一定的速度沿着固定路线走,该路线可能自交。Pandog喜欢游览沿途的景点,不过会在给定的N个点和主人相遇。小狗和主人同时从(X1,Y1)点出发,并同时在(Xn,Yn)点汇合。小狗的速度最快是Grant的两倍。当主人从一个点以直线走向另一个点时,Pandog跑向一个它感兴趣的景点。Pandog每次与主人相遇之前最多只去一个景点。

分析:

我们可以把人每次走的一条路径当作点,显然狗只能从出发点走到符合条件的部分点,把这两个点连边,表示狗要么跟人走,要么选择一条能走的路走。

求二分图最大匹配即可

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <math.h>
 5 #include <queue>
 6 using namespace std;
 7 #define N 600
 8 #define du double
 9 #define S (n+m+1)
10 #define T (n+m+2)
11 #define inf 100000000
12 int head[N],to[N*N<<1],nxt[N*N<<1],flow[N*N<<1],cnt=1,n,m,dep[N];
13 inline void add(int u,int v,int f){
14     to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;flow[cnt]=f;
15     to[++cnt]=u;nxt[cnt]=head[v];head[v]=cnt;flow[cnt]=0;
16 }
17 struct P{
18     int x,y;
19 }a[N],b[N];
20 du dis(P u,P v){
21     return sqrt((u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y));
22 }
23 bool bfs(){
24     queue <int> q;
25     q.push(S);memset(dep,0,sizeof(dep));
26     dep[S]=1;
27     while(!q.empty()){
28         int x=q.front();q.pop();
29         for(int i=head[x];i;i=nxt[i]){
30             if(!dep[to[i]]&&flow[i]){
31                 dep[to[i]]=dep[x]+1;
32                 if(to[i]==T)return 1;
33                 q.push(to[i]);
34             }
35         }
36     }
37     return 0;
38 }
39 int dfs(int x,int mf){
40     if(x==T)return mf;
41     int nf=0;
42     for(int i=head[x];i;i=nxt[i]){
43         if(dep[to[i]]==dep[x]+1&&flow[i]){
44             int tmp=dfs(to[i],min(flow[i],mf-nf));
45             nf+=tmp;
46             flow[i]-=tmp;
47             flow[i^1]+=tmp;
48             if(nf==mf)break;
49         }
50     }
51     dep[x]=0;return nf;
52 }
53 void dinic(){
54     int ans=0,f;
55     while(bfs())while(f=dfs(S,inf))ans+=f;
56     printf("%d\n",ans+n);
57     for(int i=1;i<n;i++){
58         printf("%d %d ",a[i].x,a[i].y);
59         for(int j=head[i];j;j=nxt[j]){
60             if(to[j]!=S&&flow[j]==0){
61                 printf("%d %d ",b[to[j]-n+1].x,b[to[j]-n+1].y);
62             }
63         }
64     }
65     printf("%d %d",a[n].x,a[n].y);
66 }
67 int main(){
68     scanf("%d%d",&n,&m);
69     for(int i=1;i<=n;i++){
70         scanf("%d%d",&a[i].x,&a[i].y);
71         if(i^n)add(S,i,1);
72     }
73     for(int i=1;i<=m;i++){
74         scanf("%d%d",&b[i].x,&b[i].y);
75         add(i+n-1,T,1);
76     }
77     for(int i=1;i<n;i++){
78         for(int j=1;j<=m;j++){
79             if(dis(a[i],a[i+1])>=(dis(a[i],b[j])+dis(a[i+1],b[j]))/2){
80                 add(i,j+n-1,1);
81             }
82         }
83     }
84     dinic();
85 }

原文地址:https://www.cnblogs.com/suika/p/8456979.html

时间: 2024-10-06 18:29:35

luoguP2526_[SHOI2001]小狗散步_二分图匹配的相关文章

[luoguP2526] [SHOI2001]小狗散步(二分图最大匹配)

传送门 简直就是模板题啊! #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #define N 101 using namespace std; int n, m, cnt; int X1[N], Y1[N], X2[N], Y2[N], head[N], to[N * N], nex[N * N], belong[N], ans[N]; bool vis[N

[P2526][SHOI2001]小狗散步

Link: P2526 传送门 Solution: 一道提示非常到位的题目 题面中强调了在两个路径相邻点间只能再去至多一个点,且每个点只计算一次贡献 于是明显可以将原题看作询问在两个不相交点集间最多能连几条边 接下来将合法边连上跑二分图匹配就好了 Tip:二分图匹配时分清$X,Y$集合以及$match$数组是哪个集合的匹配值 Code: #include <bits/stdc++.h> using namespace std; typedef pair<int,int> P; #d

cogs_14_搭配飞行员_(二分图匹配+最大流,网络流24题#01)

描述 http://cojs.tk/cogs/problem/problem.php?pid=14 有一些正飞行员和副飞行员,给出每个正飞行员可以和哪些副飞行员一起飞.一架飞机上必须一正一副,求最多多少飞机可以飞. 分析 裸的二分图匹配... 请叫我水题小王子... 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=100+5,INF=0x7fffffff; 5 int n,m,cnt=1; 6 int l

cogs_396_魔术球问题_(最小路径覆盖+二分图匹配,网络流24题#4)

描述 http://cojs.tk/cogs/problem/problem.php?pid=396 连续从1开始编号的球,按照顺寻一个个放在n个柱子上,\(i\)放在\(j\)上面的必要条件是\(i+j\)是一个完全平方数.问做多能放到几号球. 分析 cogs是简化版,我在网上找了个完整版的测试数据,要求输出方案... 求最大放几号球不方便,我们考虑枚举最大的球号,计算最少需要多少柱子. 我们对于满足\(j<i\)且\(i+j\)是一个完全平方数的\(i,j\),从\(j\)向\(i\)连一条

BZOJ 4443 [Scoi2015]小凸玩矩阵(二分答案+二分图匹配)

[题目链接]http://www.lydsy.com/JudgeOnline/problem.php?id=4443 [题目大意] 从矩阵中选出N个数,其中任意两个数字不能在同一行或同一列 求选出来的N个数中第K大的数字的最小值是多少. [题解] 我们二分这个第k大数字的大小,将其以上的数字全部删除, 在剩余的部分按行列连边,如果二分图匹配的数量大于n-k那么说明该答案可行. [代码] #include <cstdio> #include <algorithm> #include

矩阵游戏|ZJOI2007|BZOJ1059|codevs1433|luoguP1129|二分图匹配|匈牙利算法|Elena

1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MB Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏--矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择 矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换 对应格子的颜色)游戏的目标,即通过若干次操作,

算法讲解:二分图匹配

算法讲解:二分图匹配 二分图匹配,自然要先从定义入手,那么二分图是什么呢? 二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 简单的说,一个图被分成了两部分,相同的部分没有边,那这个图就是二分图,二分图是特殊的图. 匹配: 给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两

棋盘游戏(二分图匹配)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1281 棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3200    Accepted Submission(s): 1897 Problem Description 小 希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放

BZOJ 1854 游戏(二分图匹配或并查集)

此题的二分图匹配做法很容易想,就是把属性当做s集,武器当做t集,如果该武器拥有该武器则连一条边. 那么答案就是求该二分图的最大前i个匹配.将匈牙利算法改一改,当前找不到增广路就break. 但是过这个题需要常数优化,不能每次都fillchar一遍used数组.可以用队列将使用的used点加入,然后需要初始化的时候弹出即可. # include <cstdio> # include <cstring> # include <cstdlib> # include <i