发哥模版——你值得拥有
#define ll long long
#define MT(a,b) memset(a,b,sizeof(a));
const int INF = 0x3f3f3f3f;
const int ONF = -0x3f3f3f3f;
1.拓扑排序dfs
int way[N][N],topo[N],vis[N];
int t, n ,m;
bool dfs(int u)
{
vis[u] = -1;
for(int v=1;v<=n;v++) if(way[u][v])
{
if(vis[v]==-1) return false;
else if(!vis[v]&&!dfs(v)) return false;
}
vis[u] = 1; topo[t--] = u;
return true;
}
bool Toposort()
{
t = n;
for(int u=1;u<=n;u++) if(!vis[u])
if(!dfs(u)) return false;
return true;
}
void init()
{
memset(way,0,sizeof(way));
memset(vis,0,sizeof(vis));
memset(topo,0,sizeof(topo));
}
2.拓扑排序kahn
int n,m;
int way[N][N],cnt[N],topo[N];
void Toposort( )
{
int l = 0;
for(int i =1 ;i<=n;i++)
{
int u = 0;
for(int j=1;j<=n; j++) if(!cnt[j])
{
u = j;
break;
}
topo[++l] = u; cnt[u]=-1;
for(int v=1;v<=n;v++) if(way[u][v]) cnt[v]--;
}
}
void init()
{
memset(way,0,sizeof(way));
memset(cnt,0,sizeof(cnt));
memset(topo,0,sizeof(topo));
}
3.最小生成树prim算法
int way[maxn][maxn];
int vis[maxn],dis[maxn];//dis表示,i点到U集合的最短距离
int n,m;
int Prim(int start=0)
{
int ans = 0; MT(vis,0);
for(int i=0;i<n;i++) dis[i] = (i==start? 0 : INF);
for(int i=0;i<n;i++)
{
int min_edge = INF, k = 0;
for(int j=0;j<n;j++) if(min_edge>dis[j]&&!vis[j]) min_edge = dis[k=j];
vis[k] = 1; ans += min_edge;
for(int j=0;j<n;j++) if(!vis[j]) dis[j] = min(dis[j],way[k][j]);
}
return ans ;
}
void init()
{
for(int i=0;i<n;i++) for(int j=0 ;j<n;j++) way[i][j] = (i==j?0:INF);
}
4.并查集
int f[maxn];//i是f[i]的儿子
int Find(int x){
return f[x]==x? x : f[x]=Find(f[x]);
}
void Makeset(int n){
for(int i=0;i<=n;i++) f[i] = i;
}
void Unionset(int x,int y){
if((x=Find(x))!=(y=Find(y))) f[x] = f[y];
}
5.最小生成树 Kruskal算法
struct edge{
int u,v,vul;
};
int f[maxn];
edge E[maxn];
int Find(int x){
return f[x]==x? x : Find(f[x]);
}
void Makeset(int n){
for(int i=0;i<=n;i++) f[i] = i;
}
bool Unionset(int x,int y){
if((x=Find(x))!=(y=Find(y)))
{
f[x] = f[y]; return false;
}
return true;
}
bool compare(edge a,edge b){
return a.vul<b.vul;
}
int Kruskal(int n,int m)
{
Makeset(n); sort(E,E+m,compare);
int ans = 0;
for(int i=0;i<m;i++) if(!Unionset(E[i].u,E[i].v)) ans += E[i].vul;
for(int i=1;i<n;i++) if(Find(i)!=Find(i+1)) return -1;
return ans ;
}
6.最短路Floyd算法
int way[maxn][maxn];
void Floyd(int n)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
way[j][k] = min(way[j][k], way[j][i]+way[i][k]);
}
void init (int n){
for(int i=0;i<n;i++) for(int j=0;j<n;j++) way[i][j] = (i==j? 0:INF);
}
7.最短路Dijkstra算法O(n^2)
int way[maxn][maxn];
int dis[maxn],vis[maxn];//dis[i]表示起点到i点的最短距离
int Dijkstra(int st,int ed,int n)
{
for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
MT(vis,0);
for(int i=0;i<n;i++)
{
int min_way = INF ,k = 0;
for(int j=0;j<n;j++) if(!vis[j]&&dis[j]<=min_way) min_way = dis[k=j];
vis[k] = 1;
for(int j=0;j<n;j++) dis[j] = min(dis[j],dis[k]+way[k][j]);
}
return dis[ed];
}
void init(int n){
for(int i=0;i<n;i++)for(int j=0;j<n;j++) way[i][j] = (i==j? 0:INF);
}
8.最短路Bellman算法O(nm)
struct edge{
int u,v,vul;
};
int dis[maxn];
edge E[maxn];//若是无向图记得双向加边
int Bellman(int n,int m,int st,int ed)
{
for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
for(int i=0;i<n;i++) for(int j=0;j<m;j++)
{
int u = E[j].u, v = E[j].v, vul = E[j].vul;
if(dis[u]<INF) dis[v] = min(dis[v],dis[u]+vul);
}
return dis[ed];
}
9.最短路spfa算法(Bellman优化)
struct edge{
int to,vul;
};
int dis[maxn];
vector<edge>E[maxn];
int Spfa(int n,int st,int ed)
{
int inq[maxn];MT(inq,0);
int cnt[maxn];MT(cnt,0);
for(int i=0;i<n;i++) dis[i] = (i==st? 0:INF);
queue<int>Q; Q.push(st); inq[st] = 1;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i=0;i<E[u].size();i++)
{
int v = E[u][i].to;
int vul = E[u][i].vul;
if(dis[u]<INF&&dis[v]>dis[u]+vul)
{
dis[v] = dis[u] + vul;
if(!inq[v]) Q.push(v);
inq[v] = 1;
if(++cnt[v]>n) return -1; //存在负环,返回-1
}
}
}
return dis[ed];
}
void init(int n){
for(int i=0;i<n;i++) E[i].clear();
}
10.二分图bfs染色判断(无向图)
int way[maxn][maxn];
bool Dye(int n)
{
int vis[maxn]; MT(vis,0);
int col[maxn]; MT(col,0);
for(int i=0;i<n;i++) if(!vis[i])
{
queue<int>Q; Q.push(i);
vis[i] = 1; col[i] = 1;
while(!Q.empty())
{
int u = Q.front() ; Q.pop();
for(int v=0;v<n;v++)
{
if(way[u][v]+way[v][u]!=2) continue;//若是单向视为无边
if(!vis[v])
{
col[v] = !col[u]; vis[v] = 1;
Q.push(v);
}
else if(col[u]==col[v]) return false;
}
}
}
return true;
}
void init(int n){
MT(way,0);
}
11.二分匹配匈牙利算法
int Lx[maxn],Ly[maxn];
int vis[maxn],way[maxn][maxn];
int n,m;
int dfs(int u)
{
for(int v = 1;v <= m; v++) if(way[u][v]&&!vis[v])
{
vis[v] = 1;
if(Ly[v]==-1||dfs(Ly[v]))
{
Lx[u] = v; Ly[v] = u;
return 1;
}
}
return 0;
}
int Match()
{
int ans = 0;
for(int i=1;i<=n;i++) if(Lx[i]==-1)
{
MT(vis , 0);
ans += dfs(i);
}
return ans ;
}
void init()
{
MT(vis,0); MT(way,0);
MT(Lx,-1); MT(Ly,-1);
}
12.二分匹配KM算法O(n^3)如果只想求最大权值匹配而不要求是完备匹配的话,把各个不相连的边的权值设置为0。
#define MT(a,b) memset(a,b,sizeof(a));
const int INF = 0x3f3f3f3f;
const int ONF = -0x3f3f3f3f;
const int maxn = 1e3+5;
int way[maxn][maxn];
int Lx[maxn],Ly[maxn],slack[maxn]; //x,y的顶标和松弛量
int couple[maxn],S[maxn],T[maxn]; //组合匹配,S,T集合
int n,m,k; //x,y点的个数,组合数
bool match(int u)
{
S[u] = true;
for(int v=0;v<m;v++)
{
if(Lx[u] + Ly[v] == way[u][v] && !T[v])
{
T[v] = true;
if(couple[v]==-1||match(couple[v]))
{
couple[v] = u;
return true;
}
}
else slack[v] = min(slack[v],Lx[u] + Ly[v] - way[u][v] );
}
return false;
}
void update()
{
int a = INF;
for(int i=0;i<m;i++) if(!T[i]) a = min(a,slack[i]);
for(int i=0;i<n;i++) if(S[i]) Lx[i] -= a;
for(int i=0;i<m;i++) if(T[i]) Ly[i] += a; else slack[i] -= a;
}
int KM()
{
MT(Lx,0);MT(Ly,0);MT(couple,-1);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) Lx[i]=max(Lx[i],way[i][j]);
for(int i=0;i<n;i++)
{
for(int i=0;i<m;i++) slack[i] = INF;
while(1)
{
MT(S,0) ; MT(T,0);
if(match(i)) break;
else update();
}
}
int ans = 0,cnt = 0;
for(int i=0;i<m;i++) if(couple[i]!=-1&&way[couple[i]][i]!=ONF)
{
ans += way[couple[i]][i];
cnt ++;
}
return cnt == n? ans : -1;
}
void init()
{
MT(Lx,0);MT(Ly,0);MT(couple,-1);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) way[i][j] = ONF;
}