图算法 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; }