二分图(图论)
use1:解决矩阵横纵坐标(或者抽象成这样的关系)相互关联,求最少约束方案数量
E
给出一张由方块组成的地图。方块有许多种:墙,草,和空地。老板想让Robert在地图上放置尽可能多的机器人。每个机器人拿着一把激光枪,它可以同时向东西南北四个方向射击。机器人必须一直呆在它开始时被放在的位置并且不断地射击。激光束当然可以经过空地或草地,但不能穿过墙。机器人只能被放在空地上。当然老板不希望看到机器人相互攻击。换句话说,两个机器人不能被放在一条线上(竖直或水平),除非它们中间有一堵墙。
由于你是一位机智的程序员和Robert的好基友之一,他请你帮他解决这个问题。也就是说,给出地图的描述,计算地图上最多能放置的机器人数量。
输入格式
输入文件的第一行有两个正整数m,n(1<=m,n<=50),即地图的行数和列数。
接下来有m行,每行n个字符,这些字符是'#','*'或'o',它们分别代表墙,草和空地。
输出格式
输出一行一个正整数,即地图中最多放置的机器人数目
横纵坐标为二分图两侧,对于墙也就意味着点不能够共享横纵坐标,分开就行
const int N=70; struct node { int xx, yy; node(){ } node(int xxx,int yyy) { xx=xxx;yy=yyy; } }; int x_add[N][N],y_add[N][N],n,m,x[N][N],y[N][N]; char s[N]; vector<node>pos; struct node2 { int to,nxt; }e[N*N]; int head[N*N],tot; int max_x; inline void add(int _x,int _y) { e[++tot].to=_y,e[tot].nxt=head[_x],head[_x]=tot; } int mach[N*N],vis[N*N]; bool dfs(int x,int fa) { for(int i=head[x];i;i=e[i].nxt) { int u=e[i].to; if(u==fa)continue; if(!vis[u]) { vis[u]=1; if(!mach[u]||dfs(mach[u],u)) { mach[u]=x; return true; } } } return false; } int siz=0; void deal() { _f(i,0,siz-1) { int x_p=x[pos[i].xx][pos[i].yy],y_p=y[pos[i].xx][pos[i].yy]; add(x_p,y_p+max_x); add(y_p+max_x,x_p);//连边 } //跑匈牙利 int ans=0; _f(i,1,max_x) { memset(vis,0,sizeof(vis)); if(dfs(i,0))ans++; } chu("%d",ans); return; } int main() { //freopen("exam.txt","r",stdin); m=re(),n=re(); _f(i,1,m) { scanf("%s",s+1); _f(j,1,n) { if(s[j]=='#')//是墙 { x_add[i][j]+=1; y_add[i][j]+=1; //if(j==4)chu("y[%d][%d]+=1",i,j); } else if(s[j]=='o') { siz++; // chu("siz:%d\n",siz); pos.push_back(node(i,j)); } } } //chu("%d\n",y_add[2][4]); //处理行位置坐标列加 _f(i,1,m)//对于这一行 { _f(j,1,n) { x_add[i][j]+=x_add[i][j-1];//前缀和 x[i][j]=i+x_add[i][j]; } x_add[i+1][1]+=x_add[i][n];//别忘了把上一行的累加传下去 } max_x=m+x_add[m][n]; _f(i,1,n)//对于每一列 ,i是列!!! { _f(j,1,m)//m是行!! { y_add[j][i]+=y_add[j-1][i]; //if(i==4)chu("add[%d][%d]:%d(2,4 %d)\n",j,i,y_add[j][i],y_add[2][4]); y[j][i]=i+y_add[j][i]; //if(i==4)chu("y[%d][%d]=%d+(add)%d\n",j,i,i,y_add[j][i]); } y_add[1][i+1]+=y_add[m][i]; } //return 0; deal(); return 0; }
use2:解决求无向图最多孤立点问题,任意一点无边联通(有向图不知道)
是从一个无向图里找出几个点使得他们没有边联通
F猫和狗
F. 猫和狗 - 二分图 - 比赛 - 衡中OI (hszxoj.com)
把喜好有矛盾的两个人连一条边(没有环),跑一边匈牙利找最大匹配max(除2!)
ans=n(人的数量)-max,
就是最多选的人数,保证他们之间没有任意一条路径连通,一定不存在矛盾
use3:最小路径覆盖,有向无环图
最小路径覆盖:、
题目概述:
给你一个有向无环图,有n个点,m条有向边。
一个机器人可以从任意点开始沿着边的方向走下去。对于每一个机器人:走过的点不能再走过。
问你最少用几个机器人可以走完所有的n个点,不同的机器人可以走相同的点。
用尽量少的不相互交叉简单路径覆盖有向无环图G的所有结点(不交叉指的是原图,而非后来构造的二分图)。即覆盖点(同样地,在路径覆盖中单独一个点没有与它相连的边,也算作一次路径去覆盖这个点)。建立一个二分图模型,把所有顶点i拆成两个:X集中的i和Y集中的i',如果有边i->j,则在二分图中引入边i->j',结果就是最小路径覆盖 = N - 最大匹配数。(N为原图中结点数)
最小路径覆盖和最小边覆盖不同,不要求给的图是二分图,而是要求是N×N的有向图,且不能有环,然后根据原图构造二分图,构造方法是将点一分为二,如:i分为i`和i``然后如果i和j有边,那么就在i`和j``之间连一条边。由此构成二分图。
然后最小路径覆盖 = n-m,n为原图的点的个数,m为新造二分图的最大匹配。
若是题目要求可多次经过一个点的最小路径覆盖呢?
解决的办法是对原图进行一次闭包传递(通过Warshell传递闭包算法),于是便增加了边,然后再去求最小路径覆盖。
传递闭包概念:
一个有n个顶点的有向图的传递闭包为:有向图中的初始路径可达情况我们存入邻接矩阵A,邻接矩阵中A[i,j]表示i到j是否直接可达,若直接可达,则A[i,j]记为1,否则记为0;有向图中i到j有路径表示从i点开始经过其他点(或者不经过其他点)能够到达j点,如果i到j有路径,则将T[i,j]设置为1,否则设置为0;有向图的传递闭包表示从邻接矩阵A出发,求的是所有节点间的路径可达情况,该T矩阵就为所要求的传递闭包矩阵。(用floyed解决·)
最小路径覆盖问题求解及与最小边覆盖的区别_薄层的博客-CSDN博客_最小边覆盖
浙公网安备 33010602011771号