图论
欧拉回路
定义:给定无孤立结点图G,若存在一条路,经过G中每条边有且仅有一次,称这条路为欧拉路,如果存在一条回路经过G每条边有且仅有一次,称这条回路为欧拉回路。具有欧拉回路的图成为欧拉图。
欧拉回路存在的充要条件: 每个点的度为偶数(无向图) 每个点的入度出度相等(有向图)
欧拉路存在的必要条件: 有且仅有两个点的度为奇数(无向图) 总的入度和等于总的出度和,有且仅有两个点的入度、出度差为1,其他点相等(有向图)
匈牙利算法
最大需要**多少次?最多能匹配多少对?能否完全匹配?
/* 匈牙利算法求最大匹配数,link数组可以直接输出方案 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 210 using namespace std; int n,m,num,head[maxn],link[maxn]; bool vis[maxn]; struct node{ int to,pre; }e[maxn]; void Insert(int from,int to){ e[++num].to=to; e[num].pre=head[from]; head[from]=num; } bool dfs(int x){ for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(vis[to]==0){ vis[to]=1; if(link[to]==0||dfs(link[to])){ link[to]=x;return 1; } } } return 0; } int main(){ scanf("%d%d",&m,&n); int x,y; while(1){ scanf("%d%d",&x,&y); if(x==-1&&y==-1)break; Insert(x,y); } int ans=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof(vis)); if(dfs(i))ans++; } if(ans==0){ printf("No Solution!"); return 0; } printf("%d\n",ans); for(int i=1;i<=n;i++){ if(link[i]){ printf("%d %d\n",link[i],i); } } }
考虑如何建模,首先这是一个矩阵,矩阵上常用的建模是分离横纵坐标,根据对应位置上的数值连线
最终状态是(1,1)(2,2)...(n,n)都有一个点,我们把点看成匹配边的话,就是每行和每列都做到了匹配,换言之就是N个行和N个列都有匹配时,一定能转换成最终状态,所以就如S向每行所对应的点连边,每列所对应的点向T连边,每个1的块就是某行和某列的边,再逆过来转换到初始状态,我们发现交换行本质就是交换S向这两行连的边,所以匹配数不变,同理交换列也是
举个例子来说吧,如果有一行里有两个1,那么我们无论怎么交换行和列这两个一永远在同一行里,匹配数不变
最短路