整理一下以前做过的题用到的东西吧
---------
---图论------
(1) 最短路
1.堆优化的 dijkstra
hdu 2544
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; #define MP(a,b) make_pair(a,b) typedef long long LL; typedef pair<int,int> pii; const int INF = (1<<30)-1; const int maxn = 105; int n,m; int N,M; int first[maxn],ecnt; int dis[maxn]; struct Edge{ int v,cost,nxt; friend bool operator < (Edge a,Edge b){ return a.cost > b.cost; } }e[maxn*maxn]; void Add_edge(int u,int v,int c){ e[ecnt].v = v; e[ecnt].cost = c; e[ecnt].nxt = first[u]; first[u] = ecnt++; } void init(){ ecnt = 0; memset(first,-1,sizeof(first)); } struct cmp{ bool operator () (pii a,pii b){ return a.first > b.first; } }; int Dijkstra(int s){ priority_queue<pii,vector<pii>,cmp> PQ; fill(dis+1,dis+N+1,INF); dis[s] = 0; PQ.push(MP(dis[1],1)); while(!PQ.empty()){ pii x = PQ.top();PQ.pop(); if(dis[x.second] < x.first) continue; for(int i = first[x.second];i != -1;i = e[i].nxt){ int v = e[i].v; if(dis[v] > dis[x.second] + e[i].cost){ dis[v] = dis[x.second] + e[i].cost; PQ.push(MP(dis[v],v)); } } } return dis[N]; } int main(){ while(scanf("%d %d",&N,&M) != EOF){ if(N == 0 && M == 0) break; init(); for(int i = 1;i <= M;i++){ int a,b,c; scanf("%d %d %d",&a,&b,&c); Add_edge(a,b,c); Add_edge(b,a,c); } printf("%d\n",Dijkstra(1)); } return 0; }
2.spfa
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 9 #define MP(a,b) make_pair(a,b) 10 11 typedef long long LL; 12 typedef pair<int,int> pii; 13 const int INF = (1<<30)-1; 14 const int maxn = 105; 15 16 int n,m; 17 int N,M; 18 int first[maxn],ecnt; 19 int dis[maxn],inq[maxn]; 20 21 struct Edge{ 22 int v,cost,nxt; 23 friend bool operator < (Edge a,Edge b){ 24 return a.cost > b.cost; 25 } 26 }e[maxn*maxn]; 27 28 void Add_edge(int u,int v,int c){ 29 e[ecnt].v = v; 30 e[ecnt].cost = c; 31 e[ecnt].nxt = first[u]; 32 first[u] = ecnt++; 33 } 34 35 void init(){ 36 ecnt = 0; 37 memset(first,-1,sizeof(first)); 38 } 39 40 int Spfa(int s){ 41 queue<int> Q; 42 memset(inq,0,sizeof(inq)); 43 fill(dis+1,dis+N+1,INF); 44 Q.push(s); 45 inq[s] = 1; 46 dis[s] = 0; 47 while(!Q.empty()){ 48 int x = Q.front();Q.pop(); 49 inq[x] = 0; 50 for(int i = first[x];~i;i = e[i].nxt){ 51 int v = e[i].v; 52 if(dis[v] > dis[x] + e[i].cost){ 53 dis[v] = dis[x] + e[i].cost; 54 if(inq[v] == 0){ 55 inq[v] = 1; 56 Q.push(v); 57 } 58 } 59 } 60 } 61 return dis[N]; 62 } 63 64 int main(){ 65 while(scanf("%d %d",&N,&M) != EOF){ 66 if(N == 0 && M == 0) break; 67 init(); 68 for(int i = 1;i <= M;i++){ 69 int a,b,c; 70 scanf("%d %d %d",&a,&b,&c); 71 Add_edge(a,b,c); 72 Add_edge(b,a,c); 73 } 74 printf("%d\n",Spfa(1)); 75 } 76 return 0; 77 }
(2)最小生成树
1.堆优化的 prim
适合稠密的图
poj 1258 输入的是 N*N的邻接矩阵
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; #define MP(a,b) make_pair(a,b) typedef long long LL; typedef pair<int,int> pii; const int INF = (1<<30)-1; const int maxn = 105; int n,m; int N,M; int first[maxn],ecnt; int dis[maxn],used[maxn]; struct Edge{ int v,cost,nxt; friend bool operator < (Edge a,Edge b){ return a.cost > b.cost; } }e[maxn*maxn]; void Add_edge(int u,int v,int c){ e[ecnt].v = v; e[ecnt].cost = c; e[ecnt].nxt = first[u]; first[u] = ecnt++; } int Prim(){ priority_queue<Edge> PQ; int cnt = 0,mst = 0; memset(used,0,sizeof(used)); fill(dis+1,dis+N+1,INF); Edge s; s.v = 1,s.cost = 0; PQ.push(s); while(cnt < N){ Edge x = PQ.top();PQ.pop(); if(used[x.v]) continue; used[x.v] = 1; cnt++; mst += x.cost; for(int i = first[x.v];~i;i=e[i].nxt){ int v = e[i].v; if(!used[v] && dis[v] > e[i].cost){ dis[v] = e[i].cost; PQ.push(e[i]); } } } return mst; } void init(){ ecnt = 0; memset(first,-1,sizeof(first)); } int main(){ while(scanf("%d",&N) != EOF){ init(); for(int i = 1;i <= N;i++){ for(int j = 1;j <= N;j++){ int tmp; scanf("%d",&tmp); if(tmp) Add_edge(i,j,tmp); } } printf("%d\n",Prim()); } return 0; }
2.Kruskal
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 9 #define MP(a,b) make_pair(a,b) 10 11 typedef long long LL; 12 typedef pair<int,int> pii; 13 const int INF = (1<<30)-1; 14 const int maxn = 105; 15 16 int n,m; 17 int N,M; 18 int first[maxn],ecnt; 19 int dis[maxn],used[maxn],fa[maxn]; 20 21 struct Edge{ 22 int u,v,cost,nxt; 23 friend bool operator < (Edge a,Edge b){ 24 return a.cost < b.cost; 25 } 26 }e[maxn*maxn]; 27 28 void Add_edge(int u,int v,int c){ 29 e[ecnt].u = u; 30 e[ecnt].v = v; 31 e[ecnt].cost = c; 32 e[ecnt].nxt = first[u]; 33 first[u] = ecnt++; 34 } 35 36 int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]);} 37 38 int Kruskal(){ 39 int mst = 0; 40 sort(e,e+ecnt); 41 for(int i = 0;i < ecnt;i++){ 42 int u = e[i].u; 43 int v = e[i].v; 44 int x = find(u),y = find(v); 45 if(x != y){ 46 mst += e[i].cost; 47 fa[x] = y; 48 } 49 } 50 return mst; 51 } 52 53 void init(){ 54 ecnt = 0; 55 memset(first,-1,sizeof(first)); 56 } 57 58 59 int main(){ 60 while(scanf("%d",&N) != EOF){ 61 init(); 62 for(int i = 1;i <= N;i++) fa[i] = i; 63 for(int i = 1;i <= N;i++){ 64 for(int j = 1;j <= N;j++){ 65 int tmp; 66 scanf("%d",&tmp); 67 if(tmp) Add_edge(i,j,tmp); 68 } 69 } 70 printf("%d\n",Kruskal()); 71 } 72 return 0; 73 }
(3)无向图的割顶和桥
1.割顶
加的vis[]是为了防止重边
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int maxn = 100005; int first[maxn]; int ecnt,tot; int low[maxn],iscut[maxn],dfn[maxn]; int vis[maxn]; int N,M; struct Edge{ int u,v,nxt; }e[2*maxn]; void Add_edges(int u,int v){ e[ecnt].v = v; e[ecnt].nxt = first[u]; first[u] = ecnt++; } void init(){ ecnt = tot = 0; memset(first,-1,sizeof(first)); } void Dfs(int p,int pre){ low[p] = dfn[p] = ++tot; int son = 0; for(int i = first[p];~i;i = e[i].nxt){ if(vis[i]) continue; vis[i] = vis[i^1] = true; int v = e[i].v; if(!dfn[v]){ ++son; Dfs(v,p); low[p] = min(low[p],low[v]); if(low[v] >= dfn[p]) iscut[p] = 1;//割顶 } else low[p] = min(low[p],dfn[v]) ; } if(pre < 0 && son == 1) iscut[p] = 0; } void Tarjan(){ memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(iscut,0,sizeof(iscut)); memset(vis,0,sizeof(vis)); Dfs(1,-1); int ans = 0; for(int i = 1;i <= N;i++) ans += iscut[i]; printf("%d\n",ans); } int main(){ while(scanf("%d",&N)!=EOF && N){ init(); int a,b; char c; while(scanf("%d",&a)!=EOF&&a){ while(scanf("%d%c",&b,&c)!=EOF){ Add_edges(a,b); Add_edges(b,a); if(c=='\n') break; } } Tarjan(); } return 0; }
2.桥
ZOJ 2588
搞不清楚重边搞了好久---
vis[]标记的是对称边,,试用于有重边的情况
如果只是判断 v == pre 的话,u --- v之间就只能够访问到一条边,只有在题目说了两点之间不会有重边的时候才能这样
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int maxn = 100005; int first[maxn]; int ecnt,tot,cnt; int low[maxn],iscut[maxn],dfn[maxn]; int vis[2*maxn],bri[maxn]; int N,M,T; struct Edge{ int u,v,nxt,id; }e[2*maxn]; void Add_edges(int u,int v,int id){ e[ecnt].v = v; e[ecnt].nxt = first[u]; e[ecnt].id = id; first[u] = ecnt++; } void init(){ ecnt = tot = cnt = 0; memset(first,-1,sizeof(first)); } void Dfs(int p,int pre){ low[p] = dfn[p] = ++tot; for(int i = first[p];~i;i = e[i].nxt){ int v = e[i].v; if(vis[i]) continue; vis[i] = vis[i^1] = true; if(!dfn[v]){ Dfs(v,p); low[p] = min(low[p],low[v]); if(low[v] > dfn[p]) { bri[cnt++] = e[i].id; } } else low[p] = min(low[p],dfn[v]) ; } } void Tarjan(){ memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(iscut,0,sizeof(iscut)); memset(vis,0,sizeof(vis)); Dfs(1,-1); // for(int i = 0;i < cnt;i++) printf("bri[%d] = %d\n",i,bri[i]); sort(bri,bri+cnt); printf("%d\n",cnt); for(int i = 0;i < cnt;i++){ printf("%d",bri[i]); if(i!= cnt-1) printf(" "); } if(cnt) printf("\n"); if(T) printf("\n"); } int main(){ scanf("%d",&T); while(T--){ init(); scanf("%d %d",&N,&M); for(int i = 1;i <= M;i++){ int u,v; scanf("%d %d",&u,&v); Add_edges(u,v,i); Add_edges(v,u,i); } Tarjan(); } return 0; }
(4)强连通分量
poj 3160
有找强连通的,还有缩点
缩点之后可以转化成DAG 上的动规做,还可以spfa来做
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<stack> #include<vector> using namespace std; const int maxn = 5005; int n,m; int first[maxn]; int sc[maxn],scn[maxn],low[maxn],pre[maxn]; int scnt,ecnt,dfs_clock; int dp[maxn]; int first1[maxn]; int ecnt1; int a[maxn]; int in[maxn]; struct Edge{ int v,next; }e[maxn*10]; Edge e1[maxn*10]; stack<int> S; void init(){ ecnt = ecnt1 = 0; memset(first,-1,sizeof(first)); memset(first1,-1,sizeof(first1)); memset(dp,0,sizeof(dp)); } void addedges(int u,int v){ e[ecnt].v = v; e[ecnt].next = first[u]; first[u] = ecnt++; } void addedges1(int u,int v){ e1[ecnt1].v = v; e1[ecnt1].next = first1[u]; first1[u] = ecnt1++; } void dfs(int u){ low[u] = pre[u] = ++dfs_clock; S.push(u); for(int i = first[u];~i;i = e[i].next){ int v = e[i].v; if(!pre[v]){ dfs(v); low[u] = min(low[u],low[v]); } else if(!sc[v]) low[u] = min(low[u],pre[v]); } if(pre[u] == low[u]){ scnt++; for(;;){ int x = S.top();S.pop(); sc[x] = scnt; scn[scnt]+= a[x]; if(x == u) break; } } } void find_scc(){ while(!S.empty()) S.pop(); scnt = dfs_clock = 0; memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn)); for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); } int solve(int p){ if(dp[p]) return dp[p]; for(int i = first1[p];~i;i = e1[i].next){ int v = e1[i].v; dp[p] = max(dp[p],solve(v)); } return dp[p] = dp[p] + scn[p]; } int main(){ int T; while(scanf("%d %d",&n,&m) != EOF){ init(); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); if(a[i] < 0) a[i] = 0; } for(int i = 0;i < m;i++ ){ int u,v; scanf("%d %d",&u,&v);u++;v++; addedges(u,v); } find_scc(); memset(in,0,sizeof(in)); for(int u = 1;u <= n;u++){ for(int i = first[u];~i;i = e[i].next){ int v = e[i].v; if(sc[u] != sc[v]) addedges1(sc[u],sc[v]),in[sc[v]]++; } } int ans = 0; for(int i = 1;i <= scnt;i++) { ans = max(ans,solve(i)); } printf("%d\n",ans); } return 0; }
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<stack> #include<vector> #include<queue> using namespace std; const int maxn = 5005; const int INF = 1000000005; int n,m; int first[maxn]; int sc[maxn],scn[maxn],low[maxn],pre[maxn]; int scnt,ecnt,dfs_clock; int dp[maxn]; int du[maxn]; int dis[maxn]; int inq[maxn]; int first1[maxn]; int ecnt1; struct Edge{ int v,next; }e[maxn*10]; Edge e1[maxn*10]; stack<int> S; vector<int> g[maxn]; int val[maxn],a[maxn]; void init(){ ecnt = ecnt1 = 0; memset(first,-1,sizeof(first)); memset(val,0,sizeof(val)); memset(du,0,sizeof(du)); } void addedges(int u,int v){ e[ecnt].v = v; e[ecnt].next = first[u]; first[u] = ecnt++; } void dfs(int u){ low[u] = pre[u] = ++dfs_clock; S.push(u); for(int i = first[u];~i;i = e[i].next){ int v = e[i].v; if(!pre[v]){ dfs(v); low[u] = min(low[u],low[v]); } else if(!sc[v]) low[u] = min(low[u],pre[v]); } if(pre[u] == low[u]){ scnt++; for(;;){ int x = S.top();S.pop(); sc[x] = scnt; val[scnt] += a[x]; if(x == u) break; } } } void find_scc(){ while(!S.empty()) S.pop(); scnt = dfs_clock = 0; memset(low,0,sizeof(low));memset(pre,0,sizeof(pre)); memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn)); for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i); } int spfa(){ memset(inq, 0, sizeof(inq)); queue<int>q; g[0].clear(); q.push(0); dis[0] = 0; val[0] = 0; for(int i = 1; i <= scnt; i++){if(du[i] == 0)g[0].push_back(i); dis[i] = -INF;} int ans = 0; while(!q.empty()){ int u = q.front(); q.pop(); inq[u] = 0; for(int i = 0; i < g[u].size(); i++){ int v = g[u][i]; if(dis[v] < dis[u] + val[v]){ dis[v] = dis[u] + val[v]; ans = max(ans, dis[v]); if(inq[v] == 0)inq[v] = 1, q.push(v); } } } return ans; } int main(){ while(scanf("%d %d",&n,&m) != EOF){ init(); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); if(a[i] < 0) a[i] = 0; } for(int i = 0;i < m;i++ ){ int u,v; scanf("%d %d",&u,&v);u++;v++; addedges(u,v); } find_scc(); for(int i = 1;i <= scnt;i++) g[i].clear(); for(int u = 1;u <= n;u++){ for(int i = first[u];~i;i = e[i].next){ int v = e[i].v; if(sc[u] != sc[v]) g[sc[u]].push_back(sc[v]),du[sc[v]]++; } } printf("%d\n",spfa()); } return 0; }
(5)二分图最大匹配
poj 1274
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int maxn = 1005; int n,m; int used[maxn],mat[maxn]; vector<int> g[maxn]; void init(){ memset(mat,0,sizeof(mat)); for(int i = 1;i <= n;i++) g[i].clear(); } bool find(int p){ for(int i = 0;i < g[p].size();i++){ int v = g[p][i]; if(!used[v]){ used[v] = 1; if(!mat[v] || find(mat[v])){ mat[v] = p; return true; } } } return false; } int Hungary(){ int res = 0; for(int i = 1;i <= n;i++) { memset(used,0,sizeof(used)); if(find(i)) res++; } return res; } int main(){ while(scanf("%d %d",&n,&m) != EOF){ init(); for(int i = 1;i <= n;i++){ int a,u; scanf("%d",&a); for(int j = 1;j <= a;j++){ scanf("%d",&u); g[i].push_back(u); } } printf("%d\n",Hungary()); } return 0; }
(6)二分图最大权匹配
hdu 1533
如果是求最小权匹配的话,边权改成负的就可以了
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int M = 210; int n,nx,ny,m,r,c; int link[M],lx[M],ly[M],slack[M]; //lx,ly为顶标, slack为可改进量 int visx[M],visy[M],w[M][M]; int Dfs(int x){ visx[x] = 1; for (int y = 1;y <= ny;y ++){ if (visy[y]) continue; int t = lx[x] + ly[y] - w[x][y]; if (t == 0){ visy[y] = 1; if (link[y] == -1 || Dfs(link[y])){ link[y] = x; return 1; } } else if (slack[y] > t) slack[y] = t; } return 0; } int KM(){ int i,j; memset (link,-1,sizeof(link)); memset (ly,0,sizeof(ly)); //ly 初始化为 0 for (i = 1;i <= nx;i ++) //lx初始化为与它关联边中最大的 for (j = 1,lx[i] = -INF;j <= ny;j ++) if (w[i][j] > lx[i]) lx[i] = w[i][j]; for (int x = 1;x <= nx;x ++){ for (i = 1;i <= ny;i ++) slack[i] = INF; while (1){ memset (visx,0,sizeof(visx)); memset (visy,0,sizeof(visy)); if (Dfs(x)) //如果找到增广路,说明这个点增广完成,跳出,进入下一个点的增广 break; //如果失败的话,就要修改顶标, //方法是将在增广过程中遇到的X的顶标全部减去d,将遇到的Y的顶标全部加上d int d = INF; for (i = 1;i <= ny;i ++) if (!visy[i]&&d > slack[i]) d = slack[i]; for (i = 1;i <= nx;i ++) if (visx[i]) lx[i] -= d; for (i = 1;i <= ny;i ++) if (visy[i]) ly[i] += d; else slack[i] -= d; } } int res = 0; for (i = 1;i <= ny;i ++) if (link[i] > -1) res += w[link[i]][i]; return res; } char g[M][M]; struct node{ int x,y; }house[M],men[M]; int cal(int x,int y){ return abs(house[x].x - men[y].x) + abs(house[x].y - men[y].y); } int main(){ while(scanf("%d %d",&r,&c) != EOF && r && c){ nx = ny = 0; for(int i = 1;i <= r;i++) scanf("%s",g[i]+1); for(int i = 1;i <= r;i++){ for(int j = 1;j <= c;j++){ if(g[i][j] == 'H') house[++nx].x = i,house[nx].y = j; if(g[i][j] == 'm') men[++ny].x = i,men[ny].y = j; } } for(int i = 1;i <= nx;i++){ for(int j = 1;j <= ny;j++){ w[i][j] = -cal(i,j); } } printf("%d\n",-KM()); } return 0; }
(7) LCA
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 const int MAXN = 400010; 27 const int MAX_LOG = 32; 28 29 int T,n,m,q; 30 int first[MAXN],ecnt; 31 int fa[MAX_LOG][MAXN],dep[MAXN]; 32 ll dis[MAXN]; 33 34 int sx,sy,sz; 35 36 struct edge{ 37 int v,next,w; 38 }e[MAXN << 1]; 39 40 void Add_edge(int u,int v,int c){ 41 e[++ecnt].next = first[u]; 42 e[ecnt].v = v; 43 e[ecnt].w = c; 44 first[u] = ecnt; 45 } 46 47 void Dfs(int p,int pre,int d){ 48 fa[0][p] = pre; 49 dep[p] = d; 50 for(int i = first[p]; ~i; i = e[i].next){ 51 int v = e[i].v; 52 if(v == pre) continue; 53 dis[v] = dis[p] + e[i].w; 54 Dfs(v,p,d + 1); 55 } 56 } 57 58 void Pre(){ 59 dis[1] = 0; 60 Dfs(1,-1,0); 61 for(int k = 0; k + 1 < MAX_LOG; ++k){ 62 for(int v = 1; v <= n; ++v){ 63 if(fa[k][v] < 0) fa[k + 1][v] = -1; 64 else fa[k + 1][v] = fa[k][fa[k][v]]; 65 } 66 } 67 } 68 69 int Lca(int u,int v){ 70 if(dep[u] > dep[v]) swap(u,v); 71 for(int k = MAX_LOG - 1; k >= 0; --k){ 72 if((dep[v] - dep[u]) & (1 << k)) 73 v = fa[k][v]; 74 } 75 if(u == v) return u; //u为v的根 76 for(int k = MAX_LOG - 1; k >= 0; --k){ 77 if(fa[k][u] != fa[k][v]){ 78 u = fa[k][u]; 79 v = fa[k][v]; 80 } 81 } 82 return fa[0][u]; //u离lca只差一步 83 } 84 85 void solve(){ 86 int lcaa = Lca(sx,sy); 87 for(int i = 1;i <= q;i++){ 88 int x,y; 89 scanf("%d %d",&x,&y); 90 int lca = Lca(x,y); 91 int l = dis[x] + dis[y] - 2*dis[lca]; 92 93 int lb = sz + (dis[x] + dis[sx] - 2*dis[Lca(x,sx)]) + (dis[sy]+dis[y]-2*dis[Lca(sy,y)]); 94 int ub = sz + (dis[x] + dis[sy] - 2*dis[Lca(x,sy)]) + (dis[sx]+dis[y]-2*dis[Lca(sx,y)]); 95 96 int r = min(l,min(lb,ub)); 97 printf("%d\n",l-r); 98 } 99 } 100 101 int main(){ 102 int a,b,c; 103 scanf("%d",&T); 104 int kase = 0; 105 while(T--){ 106 MEM(first,-1); 107 ecnt = 0; 108 scanf("%d%d",&n,&q); 109 REP(i,n - 1){ 110 scanf("%d%d%d",&a,&b,&c); 111 Add_edge(a,b,c); 112 Add_edge(b,a,c); 113 } 114 115 scanf("%d %d %d",&sx,&sy,&sz); 116 117 Pre(); 118 119 printf("Case #%d:\n",++kase); 120 121 solve(); 122 } 123 return 0; 124 }
再补一个,里面的 Up(d,u)是算从u节点向上跳 d 到达的节点
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int INF = (1<<30)-1; const int maxn = 400005; const int MAX_LOG = 20; int n,m; int first[maxn],ecnt; int fa[MAX_LOG][maxn],dep[maxn]; int dp[maxn],vis[maxn]; int sz[maxn]; struct Edge{ int u,v,next,w; }; Edge e[10*maxn],ea[10*maxn]; void init(){ ecnt = 0; memset(first,-1,sizeof(first)); } void Add_edge(int u,int v){ e[ecnt].u = u; e[ecnt].v = v; e[ecnt].next = first[u]; first[u] = ecnt++; } void Dfs(int p,int pre,int d){ fa[0][p] = pre; dep[p] = d; sz[p] = 1; for(int i = first[p];~i;i = e[i].next){ int v = e[i].v; if(v == pre) continue; Dfs(v,p,d+1); sz[p] += sz[v]; } } void Pre(){ Dfs(1,-1,0); for(int k = 0;k+1 < MAX_LOG;++k){ for(int v = 1;v <= n;v++){ if(fa[k][v] < 0) fa[k+1][v] = -1; else fa[k+1][v] = fa[k][fa[k][v]]; } } } int Lca(int u,int v){ if(dep[u] > dep[v]) swap(u,v); for(int k = MAX_LOG-1;k >= 0;--k){ if(dep[v]-dep[u] & (1<<k)) v = fa[k][v]; } if(u == v) return u; for(int k = MAX_LOG-1;k >= 0;--k){ if(fa[k][u] != fa[k][v]){ u = fa[k][u]; v = fa[k][v]; } } return fa[0][u]; } int Up(int d,int u){ for(int k = MAX_LOG-1;k >= 0;k--){ if(d & (1<<k)) u = fa[k][u]; } return u; } void solve(int u,int v){ if(u == v){ printf("%d\n",n); return; } int lca = Lca(u,v); //printf("u = %d v = %d lca = %d\n",u,v,lca); int l = dep[u] + dep[v]-2*dep[lca]; if(l%2){ printf("0\n"); return; } if((u == lca && v != lca) || (u != lca && v == lca)){ int x = 0; if(u == lca) x = v; else x = u; int y = Up(l/2,x); int z = Up(l/2-1,x); // printf("x = %d y = %d lca = %d\n",x,y,lca); int res = sz[y]-sz[z]; printf("%d\n",res); } if(u != lca && v != lca){ int l = dep[u] - dep[lca]; int r = dep[v] - dep[lca]; // printf("u = %d v = %d l = %d r = %d\n",u,v,l,r); if(l == r){ int y = Up(l-1,u); int z = Up(r-1,v); // printf("===l = %d r = %d y = %d z = %d\n",l,r,y,z); int res = n-sz[y]-sz[z]; printf("%d\n",res); } else{ if(dep[u] > dep[v]) swap(u,v); int x = v; int y = Up((l+r)/2,x); int z = Up((l+r)/2-1,x); // printf("---x = %d y = %d z = %d\n",x,y,z); int res = sz[y]-sz[z]; printf("%d\n",res); } } } int main(){ while(scanf("%d",&n) != EOF){ init(); for(int i = 1;i <= n-1;i++){ int u,v; scanf("%d %d",&u,&v); Add_edge(u,v); Add_edge(v,u); } memset(sz,0,sizeof(sz)); Pre(); scanf("%d",&m); for(int i = 1;i <= m;i++){ int u,v; scanf("%d %d",&u,&v); solve(u,v); } } return 0; }
(8) 最大流
1.dinic
hdu 3549
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; const int maxn = 10005; const int INF = (1 << 30) - 1; struct Edge{ int v,next,c; }e[maxn]; int st,ed,lev[maxn],first[maxn],now[maxn],ecnt; int n,m; void init(int a,int b){ st = a; ed = b; memset(first,-1,sizeof(first)); ecnt = 0; } void addedges(int u,int v,int c){ e[ecnt].next = first[u]; e[ecnt].v = v; e[ecnt].c = c; first[u] = ecnt++; e[ecnt].next = first[v]; e[ecnt].v = u; e[ecnt].c = 0; first[v] = ecnt++; } bool bfs(){ queue<int> q; while(!q.empty()) q.pop(); q.push(st); memset(lev,-1,sizeof(lev)); lev[st] = 0; while(!q.empty()){ int x = q.front();q.pop(); for(int i = first[x];~i;i = e[i].next){ int v = e[i].v; if(lev[v] < 0 && e[i].c > 0){ lev[v] = lev[x] + 1; q.push(v); } } } return lev[ed] != -1; } int dfs(int p,int minf){ if(p == ed || minf == 0) return minf; for(int &i = now[p];~i;i = e[i].next){ int v = e[i].v; if(lev[v] == lev[p] + 1 && e[i].c > 0){ int d = dfs(v,min(e[i].c,minf)); if(d > 0){ e[i].c -= d; e[i^1].c += d; return d; } } } return 0; } int dinic(){ int max_flow = 0,p1; while(bfs()){ memcpy(now,first,sizeof(first)); while((p1 = dfs(st,INF)) > 0) max_flow += p1; } return max_flow; } int main(){ int T; int kase = 0; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); init(1,n); for(int i = 0;i < m;i++){ int a,b,c; scanf("%d %d %d",&a,&b,&c); addedges(a,b,c); } printf("Case %d: %d\n",++kase,dinic()); } return 0; }
2.ISAP
hdu 1532
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; const int maxn = 1005; const int INF = (1 << 30) - 1; struct Edge{ int from,to,cap,flow; }; vector<Edge> edges; int source; // 源点 int sink; // 汇点 int p[maxn]; // 可增广路上的上一条弧的编号 int num[maxn]; // 和 t 的最短距离等于 i 的节点数量 int cur[maxn]; // 当前弧下标 int d[maxn]; // 残量网络中节点 i 到汇点 t 的最短距离 bool visited[maxn]; int num_nodes; vector<int> G[maxn]; // 预处理, 反向 BFS 构造 d 数组 bool bfs() { memset(visited, 0, sizeof(visited)); queue<int> Q; Q.push(sink); visited[sink] = 1; d[sink] = 0; while (!Q.empty()) { int u = Q.front(); Q.pop(); for ( int i = 0;i < G[u].size();i++) { Edge &e = edges[G[u][i]^1]; if (!visited[e.from] && e.cap> e.flow) { visited[e.from] = true; d[e.from] = d[u] + 1; Q.push(e.from); } } } return visited[source]; } // 增广 int augment() { int u = sink, df = INF; // 从汇点到源点通过 p 追踪增广路径, df 为一路上最小的残量 while (u != source) { Edge &e = edges[p[u]]; df = min(df, e.cap - e.flow); u = edges[p[u]].from; } u = sink; // 从汇点到源点更新流量 while (u != source) { edges[p[u]].flow += df; edges[p[u]^1].flow -= df; u = edges[p[u]].from; } return df; } int max_flow() { int flow = 0; bfs(); memset(num, 0, sizeof(num)); for (int i = 0; i < num_nodes; i++) num[d[i]]++; int u = source; memset(cur, 0, sizeof(cur)); while (d[source] < num_nodes) { if (u == sink) { flow += augment(); u = source; } bool advanced = false; for (int i = cur[u]; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if (e.cap > e.flow && d[u] == d[e.to] + 1) { advanced = true; p[e.to] = G[u][i]; cur[u] = i; u = e.to; break; } } if (!advanced) { // retreat int m = num_nodes - 1; for ( int i = 0;i < G[u].size();i++) if (edges[G[u][i]].cap > edges[G[u][i]].flow) m = min(m, d[edges[G[u][i]].to]); if (--num[d[u]] == 0) break; // gap 优化 num[d[u] = m+1]++; cur[u] = 0; if (u != source) u = edges[p[u]].from; } } return flow; } void addedges(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0}); int m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } void init(){ edges.clear(); for(int i = 0;i < num_nodes;i++) G[i].clear(); } int main(){ int m; while(scanf("%d %d ",&m,&num_nodes) != EOF){ init(); source = 0; sink = num_nodes-1; for(int i = 0;i < m;i++){ int u,v,c; scanf("%d %d %d",&u,&v,&c);u--;v--; addedges(u,v,c); } int res = max_flow(); printf("%d\n",res); } return 0; }
(9) 最小费用最大流
poj 2135
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<stack> #include<vector> #include<queue> #include<string> using namespace std; typedef long long LL; const int maxn = 5000; const int INF = (1 << 30) - 1; int first[maxn],vis[maxn],dis[maxn],pos[maxn],ecnt,size; struct Edge{ int v,next,cap,cost; } e[10*maxn]; void init(){ ecnt = 0; memset(first,-1,sizeof(first)); } void add_edge(int u,int v,int cap,int cost){ e[ecnt].v = v; e[ecnt].cap = cap; e[ecnt].cost = cost; e[ecnt].next = first[u]; first[u] = ecnt++; e[ecnt].v = u; e[ecnt].cap = 0; e[ecnt].cost = -cost; e[ecnt].next = first[v]; first[v] = ecnt++; } bool SPFA(int s, int t) { int u,v,i; queue <int> q; memset(vis,0,sizeof(vis)); for(i= 0;i <= size;i++) dis[i]=INF; dis[s]=0; vis[s]=1; q.push(s); while(!q.empty()){ u=q.front(); q.pop(); vis[u]=0; for (i = first[u]; ~i;i = e[i].next){ v=e[i].v; if(e[i].cap > 0&& dis[u]+e[i].cost < dis[v]){ dis[v]=dis[u]+e[i].cost; pos[v]=i; if(!vis[v]){ vis[v]=1; q.push(v); } } } } return dis[t] != INF; } LL MCMF(int s,int t) { int i; LL cost=0,flow=0; while(SPFA(s,t)){ int d=INF; for (i = t;i != s;i = e[pos[i]^1].v){ d = min(d,e[pos[i]].cap); } for(i = t;i != s;i = e[pos[i]^1].v){ e[pos[i]].cap -= d; e[pos[i]^1].cap += d; } flow += d; cost += dis[t]*d; } return cost; } int main(){ int n,m; while(scanf("%d %d",&n,&m) != EOF){ init(); size = n+1; add_edge(0,1,2,0); add_edge(1,0,2,0); add_edge(n+1,n,2,0);add_edge(n,n+1,2,0); for(int i = 0;i < m;i++){ int u,v,w; scanf("%d %d %d",&u,&v,&w); add_edge(u,v,1,w); add_edge(v,u,1,w); } printf("%I64d\n",MCMF(0,n+1)); } return 0; }
又抄了一个
1 struct edge{ 2 int v,next,cost,cp; 3 }; 4 5 struct MCMF{ 6 edge e[MAXM]; 7 int sou,sin; 8 int first[MAXN],ecnt; 9 int dis[MAXN]; 10 int prev[MAXN],pree[MAXN],inq[MAXN]; 11 void init(int a,int b){ 12 sou = a; 13 sin = b; 14 memset(first,-1,sizeof(first)); 15 ecnt = 0; 16 } 17 void add_edge(int u,int v,int cap,int fee){ 18 e[ecnt].next = first[u]; 19 e[ecnt].v = v; 20 e[ecnt].cp = cap; 21 e[ecnt].cost = fee; 22 first[u] = ecnt++; 23 24 e[ecnt].next = first[v]; 25 e[ecnt].v = u; 26 e[ecnt].cp = 0; 27 e[ecnt].cost = -fee; 28 first[v] = ecnt++; 29 } 30 bool Spfa(){ 31 fill(dis,dis + MAXN,INF); 32 dis[sou] = 0; 33 MEM(prev,-1),MEM(inq,0); 34 queue<int> Q; 35 Q.push(sou); 36 while(!Q.empty()){ 37 int x = Q.front(); Q.pop(); 38 inq[x] = 0; 39 for(int i = first[x]; ~i; i = e[i].next){ 40 if(e[i].cp <= 0) continue; 41 int v = e[i].v; 42 if(dis[x] + e[i].cost < dis[v]){ 43 dis[v] = dis[x] + e[i].cost; 44 prev[v] = x; 45 pree[v] = i; 46 if(inq[v] == 0){ 47 inq[v] = 1; 48 Q.push(v); 49 } 50 } 51 } 52 } 53 if(dis[sin] > 0) return false; 54 return prev[sin] != -1; 55 } 56 int Solve(){ 57 //int sumf = 0; 58 int min_cost = 0; 59 while(Spfa()){ 60 int minf = INF; 61 for(int i = sin; i != sou; i = prev[i]){ 62 int id = pree[i]; 63 minf = min(minf,e[id].cp); 64 } 65 for(int i = sin; i != sou; i = prev[i]){ 66 int id = pree[i]; 67 e[id].cp -= minf; 68 e[id ^ 1].cp += minf; 69 } 70 //sumf += minf; 71 min_cost += dis[sin] * minf; 72 } 73 //printf("flow : %d\n",sumf); 74 return min_cost; 75 } 76 }MC;
(10) 生成树计数
/* 它的度数矩阵记为 d[][] 当 i = j 的时候,d[i][j] 为 vi的度数 当 i != j 的时候,d[i][j]为0 它的邻接矩阵记为 a[][] 当i = j 的时候, a[i][j] = 0 当 i!= j的时候,如果i到j有边的话,a[i][j] = a[j][i] = 1 它的Kirchhoff矩阵等于 == d - a 然后无向图的生成树的个数为 它的Kirchhoff矩阵的任意 n-1 阶主子式的行列式绝对值 */ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long LL; const int MAXN = 15; LL g[MAXN][MAXN]; int n,m; int d[MAXN]; LL Det(LL A[MAXN][MAXN],int n){ LL res = 1; for(int i = 1; i <= n; ++i){ for(int j = i + 1; j <= n; ++j){ while(A[j][i]){ LL t = A[i][i] / A[j][i]; for(int k = i; k <= n; ++k) A[i][k] = (A[i][k] - A[j][k] * t); for(int k = i; k <= n; ++k) swap(A[i][k],A[j][k]); res = -res; //行列式换行,值取反 } } if(!A[i][i]) return 0; res = res * A[i][i] ; } if(res < 0) res = -res; return res; } int main(){ int T; scanf("%d",&T); while(T--){ memset(g,0,sizeof(g)); memset(d,0,sizeof(d)); scanf("%d %d",&n,&m); for(int i = 1;i <= m;i++){ int u,v; scanf("%d %d",&u,&v); g[u][v] = g[v][u] = -1; d[u]++;d[v]++; } for(int i = 1;i <= n;i++) g[i][i] = d[i];//g为原图的Kirchhoff矩阵 printf("%lld\n",Det(g,n-1));//对矩阵g求一次n-1阶主子式的行列式绝对值 } return 0; }
数论
(1) 矩阵快速幂
hdu 4990
转移矩阵记得初始化
答案矩阵记得最开始弄成单位矩阵
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; //wei ziji jiayou >_< 99 typedef long long LL; int n; int mod; struct Mx{ int a[3][3]; void clear(){ for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++) a[i][j] = 0; } void stand(){ for(int i = 0;i < 3;i++){ for(int j = 0;j < 3;j++){ if(i == j) a[i][j] = 1; else a[i][j] = 0; } } } Mx operator * (const Mx &b) const { Mx c; c.clear(); for(int k = 0;k < 3;k++) for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++){ c.a[i][j] = (c.a[i][j] + (LL)a[i][k] * b.a[k][j]) % mod; } return c; } }; LL Mx_pow(int n){ Mx y,a; y.stand(); a.a[0][0] = 1;a.a[0][1] = 2;a.a[0][2] = 1; a.a[1][0] = 1;a.a[1][1] = 0;a.a[1][2] = 0; a.a[2][0] = 0;a.a[2][1] = 0;a.a[2][2] = 1; while(n){ if(n&1) y = y*a; if(n >>= 1) a = a*a; } // for(int i = 0;i < 3;i++){ // for(int j = 0;j < 3;j++) printf("%d ",y.a[i][j]); // printf("\n"); // } return y.a[0][0]%mod; } int main(){ while(scanf("%d %d",&n,&mod) != EOF){ int ans = Mx_pow(n); if(n%2 == 0) ans--; printf("%d\n",ans % mod); } return 0; }
(2) 算组合数
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int MAXN = 2000010; const ll mod = 1e9 + 7; int N; ll fac[MAXN + 10],afac[MAXN + 10]; ll Q_pow(ll x,ll y){ ll res = 1; x %= mod; while(y){ if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1; } return res; } void Pre(){ fac[0] = 1; for(int i = 1; i <= MAXN; ++i) fac[i] = fac[i - 1] * (ll)i % mod; afac[MAXN] = Q_pow(fac[MAXN],mod - 2); for(int i = MAXN; i >= 1; --i) afac[i - 1] = afac[i] * i % mod; } ll C(ll n,ll m){ if(m > n) return 0; return fac[n] * afac[n - m] % mod * afac[m] % mod; } int main(){ Pre(); scanf("%d",&N); ll ans = Q_pow(2,N+1)-1; ll cur = Q_pow(2,N); ll tmp = cur; for(int i = N+1;i <= 2*N;i++){ ll shao = 2LL*((C(i-1,N) - C(i-2,N) + mod) % mod) %mod; // printf("shao = %I64d\n",shao); tmp = (tmp-shao + mod)%mod; cur = cur + tmp; ans = (ans + cur) %mod; tmp = 2LL*tmp%mod; } printf("%I64d\n",ans); return 0; }
(3)筛一个数由哪些素数组成
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> using namespace std; typedef long long LL; const int maxn = 100005; int dp[maxn]; int Max[maxn]; vector<int> p; int vis[maxn]; int T,a[105]; int cnt[maxn]; set<long long > s; LL n; void solve( long long x){ LL y = x; // printf("y = %I64d\n",y); for(long long j = 2;1LL*j*j <= y;j++){ if(y%j == 0){ // printf("j = %I64d\n",j); while(y%j == 0){ s.insert(j); y = y/j; } } } if(y > 1) s.insert(y); // for(set<long long >::iterator it = s.begin();it != s.end();++it){ // printf("*it = %d\n",*it); //} } void work(){ if(n == 1){ puts("1"); return; } if(s.size() < 2){ printf("%I64d\n",*s.begin()); return; } LL res = 1; for(set<long long >::iterator it = s.begin();it != s.end();++it){ res = res*(*it); } printf("%I64d\n",res); } int main(){ while(scanf("%I64d",&n) != EOF){ s.clear(); solve(n); work(); } return 0; }