图算法
kurXX最小生成树
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
#define M 501
#define LIM 20000000
struct edg{
int u,v;
int w;
}all_e[M*M/2];
bool operator < (const edg &a,const edg &b){
return a.w<b.w;
}
int set[M];
inline bool uni(int set[],int a,int b){
int ac=0,a2=a,b2=b,bc=0;
while(set[a]!=0) {a=set[a];ac++;}
if(a2!=a) set[a2]=a;
while(set[b]!=0) {b=set[b];bc++;}
if(b2!=b) set[b2]=b;
if(a==b) return false;
if(ac<bc) set[a]=b;
else set[b]=a;
return true;
}
int main(){
int i,j,k,n,m,u,v,t;
cin >> t;
for(k=0;k<t;k++){
memset(set,0,sizeof(set));
cin >> n;
int ei=0;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(t!=0){
edg e;
e.u=i;e.v=j;
scanf("%d",&e.w);
if(i<j)
all_e[ei++]=e;
}
}
}
sort(&all_e[0],&all_e[ei]);
int count=0;
int size=ei;
int max=0;
for(i=0;i<size && count < n-1;i++){
if(uni(set,all_e[i].u,all_e[i].v)){
count++;
if(all_e[i].w>all_e[max].w) max=i;
}
}
printf("%d\n",all_e[max].w);
}
return 0;
}
Prim
#include <iostream>
using namespace std;
#define M 2001
int set[M]={0},g[M][M];
char str[M][8];
inline void make_map(int n,int g[M][M]){
int i,j,k;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
int c=0;
for(k=0;k<7;k++)
if(str[i][k]!=str[j][k]) c++;
g[i][j]=g[j][i]=c;
}
}
}
int main(){
int n,q[M],qf=0,ql=0,d[M],u;
char c;
scanf("%d%c",&n,&c);
int i;
while(n!=0){
memset(set,0,sizeof(set)); memset(g,0,sizeof(g));
for(i=1;i<=n;i++) {
scanf("%s",&str[i]);
q[i-1]=i;
d[i]=2000000;
}
qf=0;ql=n-1;
make_map(n,g);
int sum=0;
int f=false;
while(qf<=ql){
int min=qf;
for(i=qf+1;i<=ql;i++){
if(d[q[i]] < d[q[min]]) min=i;
}
swap(q[qf],q[min]);
u=q[qf]; qf++;
if(f) sum+=d[u];
for(i=1;i<=n;i++){
if(g[u][i] !=0 && g[u][i] < d[i]) d[i]=g[u][i];
}
f=true;
}
printf("The highest possible quality is 1/%d.\n",sum);
scanf("%d%c",&n,&c);
}
return 0;
}
堆实现最短路
#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>;
using namespace std;
#define M 1001
#define LIM 2000000000
struct dd{ //最短距离
int w,q;//w是距离值,q是堆中的相对位置
}d[M],d2[M];
struct node{
int v,w;
};
int h[M],hs;
vector<node> g[M],g2[M];
void change_key(dd d[M],int v,int w){
d[v].w=w;
int i=d[v].q;
while(i>1 && d[h[i/2]].w>d[h[i]].w){
swap(h[i],h[i/2]);
swap(d[h[i]].q,d[h[i/2]].q);
i=i/2;
}
}
inline void min_heaphy(dd d[M],int *a,int i,int s){//s 为堆大小
int l=i*2,r=i*2+1;
int miner=i;
if (l<=s && d[a[i]].w>d[a[l]].w)
miner = l;
else miner=i;
if (r<=s && d[a[miner]].w>d[a[r]].w)
miner=r;
if(miner!=i){
swap(a[i],a[miner]);
swap(d[a[i]].q,d[a[miner]].q);
min_heaphy(d,a,miner,s);
}
}
inline void init(dd d[M],int n,int s){ //初始化图和堆
int i;
hs=n;
for(i=1;i<=n;i++){d[i].w=LIM;h[i]=d[i].q=i;}
change_key(d,s,0);
}
inline void relax(dd d[M],int u,int v,int duv){
if(d[v].w>d[u].w+duv) change_key(d,v,d[u].w+duv);
}
void dijkstra(vector<node> g[M],dd d[M],int n,int s){ //n is |V| && s is the source
init(d,n,s);
int i;
while(hs!=0){
int u=h[1];
swap(h[1],h[hs]);
swap(d[h[1]].q,d[h[hs]].q);
hs--;
min_heaphy(d,h,1,hs);
for(i=0;i<g[u].size();i++) relax(d,u,g[u][i].v,g[u][i].w);
}
}
最短路DIJ普通版
#define M 101
#define LIM 20000000
int g[M][M],d[M],fd[2][M][M],gt[M][M],set[M];
inline void init(int d[M],int n,int s){ //初始化图
int i;
for(i=1;i<=n;i++) d[i]=LIM;
d[s]=0;
}
inline void relax(int d[M],int u,int v,int duv){
if(d[v]>d[u]+duv) d[v]=d[u]+duv;
}
void dijkstra(int g[M][M],int d[M],int n,int s){ //n is |V| && s is the source
init(d,n,s);
int q[M],ql=1,qf=1; //队列
int i;
for(i=1;i<=n;i++) q[ql++]=i;
while(qf!=ql){
int min=qf;
for(i=qf;i<ql;i++) if(d[q[i]]<d[q[min]]) min=i;
swap(q[qf],q[min]); //q[qf] is the min
int u=q[qf++];
for(i=1;i<=n;i++){
if(g[u][i]!=0) relax(d,u,i,g[u][i]);
}
}
}
floyd
#include <iostream>
#include <vector>
using namespace std;
#define M 301
#define LIM 200000000
int w[M][M],d[2][M][M];
void floyd(int g[M][M],int d[2][M][M],int n){
int i,j,k;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
d[0][i][j]=g[i][j];
}
d[0][i][i]=0;
} //这里是令d[0]=g
for(k=1;k<=n;k++){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
int t1=k%2; int t2=(t1+1)%2;
d[t1][i][j]=d[t2][i][j] < d[t2][i][k]+d[t2][k][j]?d[t2][i][j]:d[t2][i][k]+d[t2][k][j];
}
}
}
BELL_MAN
inline void init(int d[M],int n,int s){ //初始化图
int i;
for(i=1;i<=n;i++) d[i]=2000000000;
d[s]=0;
}
inline void relax(int d[M],int u,int v,int duv){
if(d[v]>d[u]+duv) d[v]=d[u]+duv;
}
void bell_man(int g[M][M],int d[M],int n,int s){ //n个结点 s为源点
int i,j,k;
init(d,n,s);
for(k=1;k<n;k++){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(g[i][j]!=0) relax(d,i,j,g[i][j]);
}
}
}
拓扑排序
#include <iostream>
#include <stack>
#include <vector>
#include <list>
using namespace std;
vector <int> order;
void find_id(list<int> g[],int id[],int n){ //寻找入度,没有使用
int i;
list<int>::iterator k;
for(i=0;i<n;i++){
for(k=g[i].begin();k!=g[i].end();k++){
id[*k]++;
}
}
}
void topo(list<int> g[],int id[],int n,bool &OK,bool &incon){//OK==false 表示未确定顺序 incon==true 表示发现矛盾
stack<int> s;
order.erase(order.begin(),order.end());
int t[26];
copy(&id[0],&id[n],&t[0]);
int i;
for(i=0;i<n;i++){
if(id[i]==0)
s.push(i);
}
if(s.size()!=1) OK=false;
int count=0;
while(!s.empty()){
int v=s.top(); s.pop(); count++;
order.push_back(v);
list<int>::iterator k;
for(k=g[v].begin();k!=g[v].end();k++){
id[*k]--;
if(id[*k]==0) s.push(*k);
if(s.size()>1) OK=false;
}
}
if(order.size() < n) OK=false; //矛盾发生,会导致这种情况,小心
if(count < n) incon=true;
copy(&t[0],&t[n],&id[0]);
}
DFS强连通分支
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define M 20005
vector<int> g[M],gt[M];
bool used[M];
int ft[M],sort_v[M],tim;
bool comp(const int &u,const int &v){
return ft[u]>ft[v];
}
inline int findp(int set[],int n){
int n2=n;
while(set[n]!=0) n=set[n];
if(n2!=n) set[n2]=n;
return n;
}
inline bool uni(int set[],int a,int b){
int ac=0,a2=a,b2=b,bc=0,t;
while(set[a]!=0) {a=set[a];ac++;}
while(a2!=a) {t=set[a2]; set[a2]=a; a2=t;};
while(set[b]!=0) {b=set[b];bc++;}
while(b2!=b) {t=set[b2]; set[b2]=b; b2=t;};
if(a==b) return false;
if(ac<bc) set[a]=b;
else set[b]=a;
return true;
}
void dfs(vector<int> g[M],int u){
if(used[u]) return;
tim++;
used[u]=true;
int i;
for(i=0;i<g[u].size();i++){
dfs(g,g[u][i]);
}
tim++;
ft[u]=tim;
return;
}
void dfs2(vector<int> g[],int u,int r,int set[]){
if(used[u]) return;
uni(set,u,r);
used[u]=true;
int i;
for(i=0;i<g[u].size();i++){
dfs2(g,g[u][i],u,set);
}
return;
}
void scc(int n,vector<int> g[M],int set[]){
int i,j;
tim=0;
memset(used,0,sizeof(used));
memset(set,0,sizeof(set));
for(i=1;i<=n;i++) sort_v[i]=i;
for(i=1;i<=n;i++) if(!used[i]) dfs(g,i); //compute finishing times
sort(&sort_v[1],&sort_v[n+1],comp); //decreasing f[u] order
memset(used,0,sizeof(used));
for(i=1;i<=n;i++) for(j=0;j<g[i].size();j++) gt[g[i][j]].push_back(i); //compute gt
for(i=1;i<=n;i++) if(!used[sort_v[i]]) dfs2(gt,sort_v[i],sort_v[i],set); //make the scc
}
int main(){
int i,j,n,m,u,v,set[M];
cin >> n >> m;
for(i=0;i<m;i++){
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
scc(n,g,set);
int pi=1,ptosc[M];
struct Scc{
int p,n;
}sc[M];
memset(sc,0,sizeof(sc));
for(i=1;i<=n;i++){
int p=findp(set,i);
if(sc[p].p==0) {sc[p].p=pi; ptosc[pi++]=p;}
sc[p].n++;
}
int n2=pi-1,od[M];
memset(od,0,sizeof(od));
for(i=1;i<=n;i++){
for(j=0;j<g[i].size();j++){
u=findp(set,i); v=findp(set,g[i][j]);
if(sc[u].p!=sc[v].p) od[sc[u].p]++;
}
}
int sum=0,s1=0;
for(i=1;i<=n2;i++) if(od[i]==0) {s1++; sum+=sc[ptosc[i]].n;}
if(s1!=1) sum=0;
cout << sum << endl;
}
最大匹配
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
#define M 1001
int n,m,match[M],ans[M];
bool visit[M],g[M][M];
//O(n^3)
bool dfs(int k,bool map[M][M]){
int t;
for(int i = 1; i <= m; i++){
if(map[k][i] && !visit[i]){
visit[i] = true;
t = match[i];
match[i] = k;
if(t == 0 || dfs(t,map))
return true;
match[i] = t;
}
}
return false;
}
int main(){
int i,sum=0,t,j,u,v;
cin >> t;
while(t--){
sum=0;
memset(match,0,sizeof(match));
memset(g,0,sizeof(g));
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d%d",&u,&v);
g[u][v]=true;
}
m=n;
for(i=1;i<=n; i++){
memset(visit,0,sizeof(visit));
if(dfs(i,g)) sum++;
}
cout << n-sum << endl;
}
return 0;
}
还有两个最大匹配模板
#include <iostream>
#include <string>
#include <math.h>
#include <vector>
using namespace std;
#define M 3001
bool g[M][M];
int mk[M] ,cx[M],pred[M],open[M],cy[M],nx,ny;
//边少适用O(n^3)
int MaxMatchBFS()
{
int i , u , v , t , d , e , cur , tail , res(0) ;
memset(mk , 0xff , sizeof(mk)) ;
memset(cx , 0xff , sizeof(cx)) ;
memset(cy , 0xff , sizeof(cy)) ;
for (i = 0 ; i < nx ; i++){
pred[i] = -1 ;
for (open[cur = tail = 0] = i ; cur <= tail && cx[i] == -1 ; cur++){
for (u = open[cur] , v = 0 ; v < ny && cx[i] == -1 ; v ++) if (g[u][v] && mk[v] != i)
{
mk[v] = i ; open[++tail] = cy[v] ; if (open[tail] >= 0) { pred[open[tail]] = u ; continue ; }
for (d = u , e = v ; d != -1 ; t = cx[d] , cx[d] = e , cy[e] = d , e = t , d = pred[d]) ;
}
}
if (cx[i] != -1) res++ ;
}
return res ;
}
int path(int u){
for (int v = 0 ; v < ny ; v++)
if (g[u][v] && !mk[v]){
mk[v] = 1 ;
if (cy[v] == -1 || path(cy[v])) {
cx[u] = v ;
cy[v] = u ;
return 1 ;
}
} return 0 ;
}
//少适用O(n^3)
int MaxMatchDFS()
{
int res(0) ;
memset(cx , 0xff , sizeof(cx)) ;
memset(cy , 0xff , sizeof(cy)) ;
for (int i = 0 ; i < nx ; i++)
if (cx[i] == -1){
memset(mk , 0 , sizeof(mk));
res += path(i) ;
}
return res ;
}
最大权匹配,KM算法
//此KM算法,坐标从1开始,记住
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
#define M 110
int n; // X 的大小
int lx[M], ly[M]; // 标号
bool sx[M], sy[M]; // 是否被搜索过
int match[M]; // Y(i) 与 X(match [i]) 匹配
// 从 X(u) 寻找增广道路,找到则返回 true
bool path(int u,int weight[M][M]) {
sx [u] = true;
for (int v = 0; v < n; v ++)
if (!sy [v] && lx[u] + ly [v] == weight [u] [v]) {
sy [v] = true;
if (match [v] == -1 || path(match [v],weight)) {
match [v] = u;
return true;
}
}
return false;
}
// 参数 Msum 为 true ,返回最大权匹配,否则最小权匹配
int km(bool Msum,int weight[M][M]) {
int i, j;
if (!Msum) {
for (i = 0; i < n; i ++)
for (j = 0; j < n; j ++)
weight [i] [j] = -weight [i] [j];
}
// 初始化标号
for (i = 0; i < n; i ++) {
lx [i] = -0x1FFFFFFF;
ly [i] = 0;
for (j = 0; j < n; j ++)
if (lx [i] < weight [i] [j])
lx [i] = weight [i] [j];
}
memset(match, -1, sizeof (match));
for (int u = 0; u < n; u ++)
while (1) {
memset(sx, 0, sizeof (sx));
memset(sy, 0, sizeof (sy));
if (path(u,weight))
break;
// 修改标号
int dx = 0x7FFFFFFF;
for (i = 0; i < n; i ++)
if (sx [i])
for (j = 0; j < n; j ++)
if(!sy [j])
dx = min(lx[i] + ly [j] - weight [i] [j], dx);
for (i = 0; i < n; i ++) {
if (sx [i])
lx [i] -= dx;
if (sy [i])
ly [i] += dx;
}
}
int sum = 0;
for (i = 0; i < n; i ++)
sum += weight [match [i]] [i];
if (!Msum) {
sum = -sum;
for (i = 0; i < n; i ++)
for (j = 0; j < n; j ++)
weight [i] [j] = -weight [i] [j]; // 如果需要保持 weight [ ] [ ] 原来的值,这里需要将其还原
}
return sum;
}
struct Point{
int r,c;
};
int main(){
int i,j,m;
freopen("in","r",stdin);
int w[M][M];
char c; Point pt;
while(cin >> n >> m && (n!=0 || m!=0)){
vector<Point> vh,vm;
for(i=0;i<n;i++){
getchar();
for(j=0;j<m;j++){
scanf("%c",&c);
if(c=='H'){
pt.r=i; pt.c=j;
vh.push_back(pt);
}
if(c=='m'){
pt.r=i;pt.c=j;
vm.push_back(pt);
}
}
}
for(i=0;i<vm.size();i++) for(j=0;j<vh.size();j++) w[i][j]=abs(vm[i].r-vh[j].r)+abs(vm[i].c-vh[j].c);
n=vm.size();
cout << km(false,w)<< endl;
}
}
两种欧拉路
无向图:
#define M 45
int used[M][M],id[M];
void dfs(int u,vector<int> g[],vector<int> &vans){ //O(E^2)
int j,w,v,t;
for(j=g[u].size()-1;j>=0;j--){
t=v=g[u][j]; w=u;
if(v>w) swap(v,w);
if(used[v][w]!=0){
used[v][w]--;
dfs(t,g,vans);
}
}
vans.push_back(u);
}
有向图:
int n,m;
vector<int> g[M],vans;
void dfs(int u){ //O(E^2*log(e))
int j,t;
Edg et;
for(j=g[u].size()-1;j>=0;j--){
et.u=u; et.v=g[u][j];
if(mp[et]!=0){
mp[et]--;
dfs(g[u][j]);
}
}
vans.push_back(u);
}
【最大流】Edmonds Karp
//求最小割集合的办法:
//设置一个集合A, 最开始A={s},按如下方法不断扩张A:
//1 若存在一条边(u,v), 其流量小于容量,且u属于A,则v加入A
//2 若存在(v,u), 其流量大于0,且u属于A,则v加入A
//A计算完毕,设B=V-A,
//最大流对应的割集E={(u,v) | u∈A,v∈B}
//E为割集,这是一定的
//【最大流】Edmonds Karp算法求最大流,复杂度 O(V E^2)。返回最大流,输入图容量
//矩阵g[M][M],取非零值表示有边,s为源点,t为汇点,f[M][M]返回流量矩阵。
int f[M][M],g[M][M];
int EdmondsKarp(int n,int s,int t){
int i,j,k,c,head,tail,flow=0;
int r[M][M];
int prev[M],visit[M],q[M];
for (i=1;i<=n;i++) for (j=1;j<=n;j++) {f[i][j]=0;r[i][j]=g[i][j];} //初始化流量网络和残留网络
while (1) { //在残留网络中找到一条s到t的最短路径
head=tail=0;
memset(visit,0,sizeof(visit));
q[tail++]=s;
prev[s]=-1; visit[s]=1;
while(head!=tail){ //宽度优先搜索从s到t的最短路径
k=q[head++];
for (i=1;i<=n;i++)
if (!visit[i] && r[k][i]>0) {
visit[i]=1;
prev[i]=k;
if (i==t) goto next;
q[tail++]=i;
}
}
next:
if (!visit[t]) break; //流量已达到最大
c=99999999;
j=t;
while (j!=s) {
i=prev[j];
if (c>r[i][j]) c=r[i][j];
j=i;
}
//下面改进流量
j=t;
while (j!=s) {
i=prev[j];
f[i][j]+=c;
f[j][i]=-f[i][j];
r[i][j]=g[i][j]-f[i][j];
r[j][i]=g[j][i]-f[j][i];
j=i;
}
flow+=c;
//cout << c << endl;
}
return flow;
}
dinic
/*
dinic
BFS+多路增广
这个模板是OIBH上的Code_Rush的,他写的Dinic和别人的不太一样,速度更快
O(mn^2)
*/
#include<stdio.h>
#include<list>
#include<queue>
#include<string.h>
#include <vector>
#include <iostream>
using namespace std;
#define M 201
int pre[M];
int f[M][M],g[M][M];
bool b[M]={0};
//g为输入的图容量矩阵,f为返回流量矩阵
int dinic(int n,int s,int t)
{
memset(f,0,sizeof(f));
int ans=0;
while(true)
{
queue<int> q;
fill(pre,pre+n+2,-1);
fill(b,b+n+2,0);
q.push(s);b[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
if(x==t)break;
for(int i=1;i<=n;i++)
{
if(!b[i]&&f[x][i]<g[x][i])
{
pre[i]=x;
b[i]=1;
q.push(i);
}
}
}
if(pre[t]==-1)break;
for(int i=1;i<=n;i++)
{
if(f[i][t]<g[i][t]&&(i==s||pre[i]!=-1))
{
int v,low=g[i][t]-f[i][t];
pre[t]=i;
for(v=t;pre[v]!=-1;v=pre[v])
low=low<g[pre[v]][v]-f[pre[v]][v]?low:g[pre[v]][v]-f[pre[v]][v];
if(low==0)continue;
for(v=t;pre[v]!=-1;v=pre[v])
{
f[pre[v]][v]+=low;
f[v][pre[v]]-=low;
}
ans+=low;
}
}
}
return ans;
}
int main(){
int m,n,i,j,u,v,w;
while(cin >> m >> n){
memset(g,0,sizeof(g));
for(i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
g[u][v]+=w;
}
cout << dinic(n,1,n) << endl;
}
}
【最小费用最大流】Edmonds Karp对偶算法
#define M 211
#define LIM 99999999
//【最小费用最大流】Edmonds Karp对偶算法,复杂度 O(V^3E^2)。返回最大流,输入图
//容量矩阵g[M][M],费用矩阵w[M][M],取非零值表示有边,s为源点,t为汇点,f[M][M]返
//回流量矩阵,minw返回最小费用。
int g[M][M],w[M][M],minw,f[M][M];
int DualityEdmondsKarp(int n,int s,int t){
int i,j,k,c,quit,flow=0;
int best[M],prev[M];
minw=0;
for (i=1;i<=n;i++) {
for (j=1;j<=n;j++){
f[i][j]=0;
if (g[i][j]) {g[j][i]=0;w[j][i]=-w[i][j];}
}
}
while (1) {
for (i=1;i<=n;i++) best[i]=LIM;
best[s]=0;
do {
quit=1;
for (i=1;i<=n;i++){
if (best[i]<LIM)
for (j=1;j<=n;j++){
if (f[i][j]<g[i][j] && best[i]+w[i][j]<best[j]){
best[j]=best[i]+w[i][j];
prev[j]=i;
quit=0;
}
}
}
}while(!quit);
if (best[t]>=LIM) break;
c=LIM;
j=t;
while (j!=s) {
i=prev[j];
if (c>g[i][j]-f[i][j]) c=g[i][j]-f[i][j];
j=i;
}
j=t;
while (j!=s) {
i=prev[j];
f[i][j]+=c;
f[j][i]=-f[i][j];
j=i;
}
flow+=c; minw+=c*best[t];
}
return flow;
}
ACM+算法集--常用ACM算法
最新推荐文章于 2025-08-18 15:35:46 发布