关键词: 后缀数组 AC自动机 AC+dp 分数规划 二分图最小权 二分图最大权 2-sat 最大流 最短路径(负环判定)
最小生成树(kruskal、并查集) 最小生成树prim stl优先队列的简单用法 二分图最大匹配 康托展开 最小费用(最大)流 日期
kd树
1.后缀数组
#include <cstdio> #include <string> #include <vector> #include <cstring> #include <utility> #include <algorithm> using namespace std; const int MAXN = 100005; int sa[MAXN], rank[MAXN], height[MAXN]; char str[MAXN]; int wa[MAXN], wb[MAXN], wv[MAXN], ws[MAXN]; inline bool cmp(int *r, int a, int b, int len){ return (r[a]==r[b]) && (r[a+len]==r[b+len]); } void sortSA(char *r, int *sa, int n, int m){//r为字符串数组,sa为后缀数组,n=strlen(s)+1,m为max(r[i])+1。 int i, j, p, *x = wa, *y = wb, *t; //对长度为1的字符串基数排序。 for(i = 0; i < m; i++) ws[i] = 0;//清零。 for(i = 0; i < n; i++) ws[x[i]=r[i]]++;//统计各相同字符的个数。 for(i = 1; i < m; i++) ws[i] += ws[i-1];//统计小于等于i的字符共有多少个。 for(i = n-1; i >= 0; i--) sa[--ws[x[i]]] = i;//小于等于r[i]共有ws[x[i]]个,因此r[i]排在第ws[x[i]]个。 for(j = p = 1; p < n; j <<= 1, m = p){//p是第二关键字为0的个数,j是当前比较的字符串长度. //对第二关键字基数排序。 //y[s]=t表示排在第s个的起点在t,即y[s]对第二关键字排序,但y[s]的值指向第一关键字的位置。 for(p=0, i=n-j; i < n; i++) y[p++] = i;//在n-j之后的第二关键字都为0,排在前面,即第p个。 for(i = 0; i < n; i++){ if(sa[i] >= j)//如果排在第i个的字符串起点在sa[i],满足sa[i]>=当前字符串长度j。 y[p++] = sa[i] - j;//对于sa[i]-j为起点的第二关键字排在前面。 } //对第一关键字基数排序。 for(i = 0; i < m; i++) ws[i] = 0;//清零。 for(i = 0; i < n; i++) ws[wv[i]=x[y[i]]]++;//第二关键字排在第i个的起点在y[i],x[y[i]]就是y[i]指向的字符,ws进行个数统计。 for(i = 1; i < m; i++) ws[i] += ws[i-1];//统计字符小于等于i的个数。 for(i = n-1; i >= 0; i--)//wv[i]是排在第i个第二关键字对应的第一关键字。 sa[--ws[wv[i]]] = y[i];//y[i]就是第一关键字的位置。 for(t=x,x=y,y=t,x[sa[0]]=0,p=i=1; i < n; i++)//交换x,y的地址,x保存当前rank值,y为前一次rank值。 x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p-1:p++; //若rank[sa[i-1]]=rank[sa[i]],则必然sa[i-1]+j没有越界,因为不可能有相等的后缀。 } } /*height 数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公 共前缀,也就是排名相邻的两个后缀的最长公共前缀。那么对于j 和k,不妨设 rank[j]<rank[k],则有以下性质: suffix(j) 和suffix(k) 的最长公共前缀为height[rank[j]+1], height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。 */ void calHeight(char *r, int *sa, int n){ //n为字符数组r的长度 int i, j, k = 0; for(i = 1; i <= n; i++) rank[sa[i]] = i; for(i = 0; i < n; i++){ for(k? k--:0, j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++); height[rank[i]] = k; } } int main() { freopen("data.in", "r", stdin); scanf("%s", str); int len = strlen(str); sortSA(str, sa, len+1, 255); calHeight(str, sa, len); printf("%s\n", str); for(int i = 1; i <= len; i++) printf("%d ", sa[i]); printf("\n"); for(int i = 1; i <= len; i++) printf("%d ", height[i]); printf("\n"); return 0; }
2.AC自动机
struct node { int ct; node *pre, *next[26]; void init() { ct = 0; pre = 0; memset(next, 0, sizeof(next)); } }; int cnt; //节点总数 node *root, trie[500010]; node *queue[500010]; void insertStr(node *root, char *str) { int index, len = strlen(str); for(int i = 0; i < len; i++) { index = str[i]-'a'; if(root->next[index] == 0) { root->next[index] = &trie[++cnt]; root->next[index]->init(); } root = root->next[index]; } root->ct++; } void buildAC() { int head, tail; node *u, tmp; queue[0] = root; root->pre = root; head = tail = 0; while(head <= tail) { u = queue[head++]; for(int i = 0; i < 26; i++) { if(u->next[i] == 0) { if(u == root) u->next[i] = root; else u->next[i] = u->pre->next[i]; } else { if(u == root) u->next[i]->pre = root; else u->next[i]->pre = u->pre->next[i]; queue[++tail] = u->next[i]; } } } }
3.AC+dp
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <map> #include <string> #include <utility> #include <algorithm> using namespace std; const int N = 10; struct node { int num, index; node *pre, *next[4]; void init() { num = index = 0; pre = 0; memset(next, 0, sizeof(next)); } }; int n, l, cnt, val[10], sval[1<<N]; bool dp[2][N*150][1<<N]; char str[150]; map <char, int> h; node trie[N*150]; node *root, *queue[N*150]; void insertStr(node *root, char *str, int pos) { int lab, len = strlen(str); for(int i = 0; i < len; i++) { lab = h[str[i]]; if(root->next[lab] == NULL) { root->next[lab] = &trie[++cnt]; root->next[lab]->init(); root->next[lab]->index = cnt; } root = root->next[lab]; } root->num |= (1<<pos); } void buildAC() { int head, tail; node *u; root->pre = root; head = tail = 0; queue[0] = root; while(head <= tail) { u = queue[head++]; u->num |= u->pre->num; for(int i = 0; i < 4; i++) { if(u->next[i] == 0) { if(u == root) u->next[i] = root; else u->next[i] = u->pre->next[i]; } else { if(u == root) u->next[i]->pre = root; else u->next[i]->pre = u->pre->next[i]; queue[++tail] = u->next[i]; } } } } int main() { //freopen("data.in", "r", stdin); h['A'] = 0; h['G'] = 1; h['T'] = 2; h['C'] = 3; while(scanf("%d%d", &n, &l) != EOF) { memset(trie, 0, sizeof(trie)); root = &trie[0]; root->init(); cnt = 0; for(int i = 0; i < n; i++) { scanf(" %s%d", str, &val[i]); insertStr(root, str, i); } memset(sval, 0, sizeof(sval)); for(int state = 0; state < (1<<n); state++) { for(int j = 0; j < n; j++) if(state&(1<<j)) sval[state] += val[j]; } buildAC(); memset(dp, false, sizeof(dp)); int u, v; u = 0; dp[u][0][0] = true; for(int i = 0; i < l; i++) { v = u^1; memset(dp[v], false, sizeof(dp[v])); for(int j = 0; j <= cnt; j++) for(int k = 0; k < (1<<n); k++) { if(!dp[u][j][k]) continue; else { for(int p = 0; p < 4; p++) { int dindex = trie[j].next[p]->index; dp[v][dindex][k|trie[dindex].num] = true; } } } u = v; } int ans = -1; for(int i = 0; i <= cnt; i++) for(int j = 0; j < (1<<n); j++) { if(dp[u][i][j] == false) continue; ans = max(ans, sval[j]); } if(ans != -1) printf("%d\n", ans); else printf("No Rabbit after 2012!\n"); } return 0; }
4.分数规划
(1) 一般分数规划的解法 简单总结一下解分数规划的一般步骤吧: 1. 对于最小化目标函数r = ax/bx,则构造函数g(r)=min{ax - r*bx} 对于最大化目标函数r = ax/bx,则构造函数g(r)=max{ax - r*bx} 2. 由各种大科学家大神们证明得结论T_T: (1)g(r)是单调减函数(有些离散情况下也有可能是单调不增加函数),即随r的增加而减小。 (2)若r是最优解,则g(r)==0。。 3. 建立模型二分r求解。
5.二分图最小权
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <utility> using namespace std; const int N =105; const int M =10005; const int inf =0x1fffffff; int n, m, tot, lx[N], ly[N], match[N], h[N], v[M], w[M], nxt[M]; bool visx[N], visy[N]; int lack; void add(int a, int b, int c) { v[tot] = b; w[tot] = c; nxt[tot] = h[a]; h[a] = tot++; } bool find(int u) { int i, t; visx[u] =true; for(i = h[u]; i !=-1; i = nxt[i]) if(!visy[v[i]]) { t = w[i] - lx[u] - ly[v[i]]; if(t ==0) { visy[v[i]] =true; if(match[v[i]]==-1|| find(match[v[i]])) { match[v[i]] = u; return true; } } else if(t >0) lack = min(lack, t); } return false; } int calMatch(int n) { int ans = 0; for(int i =1; i <= n; i++) { lx[i] = inf; ly[i] =0; for(int j = h[i]; j !=-1; j = nxt[j]) lx[i] = min(lx[i], w[j]); } memset(match, -1, sizeof(match)); for(int i =1; i <= n; i++) { memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); lack = inf; while(!find(i)) { for(int j =1; j <= n; j++) { if(visx[j]) lx[j] += lack; if(visy[j]) ly[j] -= lack; } memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); } } ans = 0; for(int i =1; i <= n; i++) ans = ans + lx[i] + ly[i]; return ans; }
6.二分图最大权
#include <iostream> #include <cstdio> #include <cstring> usingnamespace std; constint N =310; constint inf =0x1fffffff; int n, lx[N], ly[N], match[N], w[N][N]; bool visx[N], visy[N]; int lack; int getNum() { char c; int ans =0; c = getchar(); while(c<'0'|| c>'9') c = getchar(); while(c>='0'&& c<='9') { ans = ans*10+c-'0'; c = getchar(); } return ans; } bool find(int u) { int i, t; visx[u] =true; for(i =1; i <= n; i++) if(!visy[i]) { t = lx[u] + ly[i] - w[u][i]; if(t ==0) { visy[i] =true; if(match[i]==-1|| find(match[i])) { match[i] = u; returntrue; } } elseif(t >0) lack = min(lack, t); } returnfalse; } int main() { int i, j, ans; while(scanf("%d", &n) != EOF) { for(i =1; i <= n; i++) { lx[i] = ly[i] =0; for(j =1; j <= n; j++) { w[i][j] = getNum(); lx[i] = max(lx[i], w[i][j]); } } memset(match, -1, sizeof(match)); for(i =1; i <= n; i++) { memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); lack = inf; while(!find(i)) { for(j =1; j <= n; j++) { if(visx[j]) lx[j] -= lack; if(visy[j]) ly[j] += lack; } memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); } } ans =0; for(i =1; i <= n; i++) ans = ans + lx[i] + ly[i]; printf("%d\n", ans); } return0; }
7. 2-sat
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 1010; int n; //原图中共有2*n个相对的节点。 int ct, depth, top, index[N<<1], d[N<<1], low[N<<1], stack[N<<1]; bool instack[N<<1], map[N<<1][N<<1], g[N<<1][N<<1]; int tot, et[N<<1], color[N<<1], op[N<<1]; bool visit[N<<1]; void initData() { //初始化数据,根据题意建图,建好的初始图为map ........ } void dfs(int u) { //tarjan求强连通分量,缩点 int i, x; d[u] = low[u] = depth++; stack[++top] = u; instack[u] =true; for(i = 0; i < n+n; i++) if(map[u][i]) { if(d[i] == -1) { dfs(i); low[u] = min(low[u], low[i]); } else { if(instack[i]) low[u] = min(low[u], d[i]); } } if(low[u] == d[u]) { ct++; while(top) { x = stack[top--]; instack[x] = false; index[x] = ct; if(x == u) break; } } } void buildNewGraph() { //根据缩点建立新图 int i, j; memset(g, false, sizeof(g)); for(i = 0; i < n+n; i++) for(j = 0; j < n+n; j++) if(map[i][j]) g[index[i]][index[j]] = true; for(i = 1; i <= ct; i++) for(j = i+1; j <= ct; j++) swap(g[i][j], g[j][i]); //将新图中的边反向 for(i = 0; i < n; i++) { //根据原图的矛盾节点确定新图的矛盾节点 op[index[i]] = index[i+n]; op[index[i+n]] = index[i]; } } void transDfs(int u) { int i; visit[u] =true; for(i = 1; i <= ct; i++) if(!visit[i] && g[u][i]) transDfs(i); et[++tot] = u; } void colorDfs(int u) { int i; color[u] = 0; for(i = 1; i <= ct; i++) if(color[i]==-1 && g[u][i]) colorDfs(i); } void generateAns() { int i; memset(visit, false, sizeof(visit)); tot = 0; //拓扑排序 for(i = 1; i <= ct; i++) if(!visit[i]) transDfs(i); memset(color, -1, sizeof(color)); for(i = ct; i > 0; i--) if(color[et[i]] == -1) { color[et[i]] = 1; //选择第一个未着色的顶点x, 把x染成红色1, 并把与之矛盾的节点y及其所有子孙节点染成蓝色0。 colorDfs(op[et[i]]); } } void solve() { int i; depth = top = ct =0; memset(d, -1, sizeof(d)); memset(instack, false, sizeof(instack)); for(i = 0; i < n+n; i++) if(d[i] == -1) dfs(i); for(i = 0; i < n; i++) if(index[i] == index[i+n]) break; if(i < n) printf("NO\n"); else { printf("YES\n"); buildNewGraph(); generateAns(); //printAns(); } } int main() { initData(); solve(); return 0; }
8. 最大流
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <utility> #include <algorithm> using namespace std; const int Maxn = 20005; const int Maxm = (200005<<1)+(Maxn<<1); const int inf = 0x1fffffff; int n, m, queue[Maxn], lab[Maxn]; int tot, h[Maxn], nxt[Maxm<<1], v[Maxm<<1], res[Maxm<<1]; void addEdge(int a, int b, int c) { v[tot] = b; res[tot] = c; nxt[tot] = h[a]; h[a] = tot++; v[tot] = a; res[tot] = 0; nxt[tot] = h[b]; h[b] = tot++; } bool bfs(int s, int t) { int head, tail, u; memset(lab, -1, sizeof(lab)); lab[s] = head = tail =0; queue[0] = s; while(head <= tail) { u = queue[head++]; for(int i = h[u]; i != -1; i = nxt[i]) if(res[i]>0 && lab[v[i]]==-1) { lab[v[i]] = lab[u] +1; queue[++tail] = v[i]; } } if(lab[t] != -1) return true; else return false; } int dinicDfs(int delta, int u, int t) { int sum =0, tmp; if(u == t) return delta; else { for(int i = h[u]; i != -1; i = nxt[i]) if(lab[v[i]]==lab[u]+1 && res[i]>0) { tmp = dinicDfs(min(delta, res[i]), v[i], t); sum += tmp; delta -= tmp; res[i] -= tmp; res[i^1] += tmp; if(delta == 0) break; } if(sum == 0) lab[u] = -1; return sum; } } int maxFlow(int s, int t) { int ans =0; while(bfs(s, t)) ans += dinicDfs(inf, s, t); return ans; } int main() { int a, b, c, s, t; freopen("data.txt", "r", stdin); while(scanf("%d%d", &n, &m) != EOF) { s = 0; t = n+1; tot = 0; for(int i = 0; i <= t; i++) h[i] = -1; for(int i = 1; i <= n; i++) { scanf("%d%d", &a, &b); addEdge(s, i, a); addEdge(i, t, b); } while(m--) { scanf("%d%d%d", &a, &b, &c); addEdge(a, b, c); addEdge(b, a, c); } int ans = maxFlow(s, t); cout << ans << endl; } return 0; }
9.最短路径(spfa判负环)
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int N = 550; const int M = 3000<<1; int Case, n, m, w; int tot, h[N], nxt[M], c[M], v[M]; int used[N], dis[N]; bool visit[N]; void add(int s, int t, int e) { v[tot] = t; c[tot] = e; nxt[tot] = h[s]; h[s] = tot++; } bool spfa(int s) { int u; queue <int> q; while(!q.empty()) q.pop(); memset(visit, false, sizeof(visit)); memset(used, 0, sizeof(used)); for(int i = 1; i <= n; i++) dis[i] = 0x1fffffff; dis[0] = 0; used[0] = 1; q.push(s); while(!q.empty()) { u = q.front(); q.pop(); visit[u] = false; for(int p = h[u]; p != -1; p = nxt[p]) { if(dis[v[p]] > dis[u] + c[p]) { dis[v[p]] = dis[u] + c[p]; if(!visit[v[p]]) { visit[v[p]] = true; q.push(v[p]); used[v[p]]++; if(used[v[p]] >= n) return true; } } } } return false; } int main() { int s, t, e; scanf("%d", &Case); while(Case--) { scanf("%d%d%d", &n, &m, &w); memset(h, -1, sizeof(h)); tot = 0; for(int i = 0; i < m; i++) { scanf("%d%d%d", &s, &t, &e); add(s, t, e); add(t, s, e); } for(int i = 0; i < w; i++) { scanf("%d%d%d", &s, &t, &e); add(s, t, -e); } for(int i = 1; i <= n; i++) add(0, i, 0); if(spfa(0)) printf("YES\n"); else printf("NO\n"); } return 0; }
10. 最小生成树 (kruskal、并查集)
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 200010; struct node { int x, y, cost; }e[N]; int n, m, father[N]; bool cmp(const node &a, const node &b) { return a.cost < b.cost; } int getFather(int u) { if(father[u] != u) father[u] = getFather(father[u]); return father[u]; } int kruskal() { int fa, fb, sum = 0; for(int i = 0; i < n; i++) father[i] = i; sort(e, e+m, cmp); for(int i = 0; i < m; i++) { fa = getFather(e[i].x); fb = getFather(e[i].y); if(fa == fb) continue; else { father[fb] = father[fa]; sum += e[i].cost; } } return sum; } int main() { int tot; freopen("data.in", "r", stdin); while(scanf("%d%d", &n, &m) != EOF) { if(n==0 && m==0) break; tot = 0; for(int i = 0; i < m; i++) { scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].cost); tot += e[i].cost; } int ans = tot-kruskal(); printf("%d\n", ans); } return 0; }
11.最小生成树prim
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int N = 105; int Case, n; bool visit[N]; double x[N], y[N], dis[N], g[N][N]; double Cal(int a, int b) { double tx=x[a]-x[b], ty=y[a]-y[b]; return sqrt(tx*tx + ty*ty); } double prim() { double tot = 0.0, min; int v; for(int i = 1; i <= n; i++) dis[i] = g[1][i]; memset(visit, false, sizeof(visit)); visit[1] = true; for(int k = 1; k < n; k++) { min = 1e8; for(int i = 1; i <= n; i++) { if(!visit[i] && min>dis[i]) { min = dis[i]; v = i; } } visit[v] = true; for(int i = 1; i <= n; i++) { if(!visit[i] && dis[i]>g[v][i]) { dis[i] = g[v][i]; } } tot += min; } return tot; } int main() { freopen("data.in", "r", stdin); scanf("%d", &Case); while(Case--) { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]); for(int i = 1; i <= n; i++) { g[i][i] = 0.0; for(int j = i+1; j <= n; j++) { g[i][j] = g[j][i] = Cal(i, j); } } double ans = prim(); printf("%.2f\n", ans); if(Case) printf("\n"); } return 0; }
12. stl优先队列的简单用法
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; struct comp { bool operator () (int a, int b) { return a > b; } }; int main() { freopen("data.in", "r", stdin); priority_queue <int, vector<int>, comp> q; q.push(11); q.push(0); q.push(22); q.push(16); q.push(6); q.push(8); q.push(100); while(!q.empty()) { int x = q.top(); q.pop(); cout << x << endl; } return 0; } 输出: 0 6 8 11 16 22 100
13. 二分图最大匹配
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 105; const double eps = 1e-6; struct node { double x, y; }; int n, m, s, v, match[N]; bool visit[N], g[N][N]; node c[N], h[N]; double Cal(const node &a, const node &b) { double tx, ty; tx = a.x-b.x; ty = a.y-b.y; return sqrt(tx*tx+ty*ty); } int cmp(double x) { if(x > eps) return 1; else if(x < -eps) return -1; else return 0; } bool find(int u) { for(int i = 0; i < m; i++) { if(g[u][i] && !visit[i]) { visit[i] = true; if(match[i]==-1 || find(match[i])) { match[i] = u; return true; } } } return false; } int maxMatch() { int ans = 0; memset(match, -1, sizeof(match)); for(int i = 0; i < n; i++) { if(find(i)) ans++; memset(visit, false, sizeof(visit)); } return ans; } int main() { double tmp; while(scanf("%d%d%d%d", &n, &m, &s, &v) != EOF) { for(int i = 0; i < n; i++) scanf("%lf%lf", &c[i].x, &c[i].y); for(int i = 0; i < m; i++) scanf("%lf%lf", &h[i].x, &h[i].y); memset(g, false, sizeof(g)); for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) { tmp = Cal(c[i], h[j]); if(cmp(tmp/v - s) < 0) g[i][j] = true; } int mm = maxMatch(); printf("%d\n", n-mm); } return 0; }
14. 康托展开
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 10; int p[N], fac[N]; int Cal(int p[], int n) { int ans = 0; for(int i = 0; i < n; i++) { int ct = 0; for(int j = i+1; j < n; j++) { if(p[j] < p[i]) ct++; } ans += ct*fac[n-i-1]; } return ans+1; } int main() { int n; fac[0] = 1; for(int i = 1; i < N; i ++) fac[i] = fac[i-1]*i; while(cin >> n) { for(int i = 0; i < n; i++) cin >> p[i]; int ans = Cal(p, n); cout << ans << endl; } return 0; }
15. 最小费用(最大)流
#include <iostream> #include <algorithm> #include <string> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <cmath> using namespace std; int sumFlow; const int MAXN = 1010; const int MAXM = 1000200; const int INF = 1000000000; struct Edge { int u, v, cap, cost; int next; }edge[MAXM<<2]; int NE; int head[MAXN], dist[MAXN], pp[MAXN]; bool vis[MAXN]; void init() { NE = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, int cost) { edge[NE].u = u; edge[NE].v = v; edge[NE].cap = cap; edge[NE].cost = cost; edge[NE].next = head[u]; head[u] = NE++; edge[NE].u = v; edge[NE].v = u; edge[NE].cap = 0; edge[NE].cost = -cost; edge[NE].next = head[v]; head[v] = NE++; } bool SPFA(int s, int t, int n) { int i, u, v; queue <int> qu; memset(vis,false,sizeof(vis)); memset(pp,-1,sizeof(pp)); for(i = 0; i <= n; i++) dist[i] = INF; vis[s] = true; dist[s] = 0; qu.push(s); while(!qu.empty()) { u = qu.front(); qu.pop(); vis[u] = false; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].cap && dist[v] > dist[u] + edge[i].cost) { dist[v] = dist[u] + edge[i].cost; pp[v] = i; if(!vis[v]) { qu.push(v); vis[v] = true; } } } } if(dist[t] == INF) return false; return true; } int MCMF(int s, int t, int n) // minCostMaxFlow { int flow = 0; // 总流量 int i, minflow, mincost; mincost = 0; while(SPFA(s, t, n)) { minflow = INF + 1; for(i = pp[t]; i != -1; i = pp[edge[i].u]) if(edge[i].cap < minflow) minflow = edge[i].cap; flow += minflow; for(i = pp[t]; i != -1; i = pp[edge[i].u]) { edge[i].cap -= minflow; edge[i^1].cap += minflow; } mincost += dist[t] * minflow; } sumFlow = flow; // 最大流 return mincost; }
16. 日期
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; class Date { public: //判断是否闰年 inline static bool isLeap(int year) { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } int year, month, day; Date() {} Date(int y, int m, int d) : year(y), month(m), day(d) {} //判断日期是否合法 inline bool isLegal() const { if (month <= 0 || month > 12) { return false; } if (month == 2) { return day > 0 && day <= 28 + isLeap(year); } return day > 0 && day <= days[month - 1]; } //与另一个日期比较 inline int compareTo(const Date &other) const { if (year != other.year) { return year - other.year; } if (month != other.month) { return month - other.month; } return day - other.day; } //返回当前日期是星期几 0 (Sunday) ... 6 (Saturday) inline int toWeekday() const { int tm = month >= 3 ? (month - 2) : (month + 10); int ty = month >= 3 ? year : (year - 1); return (ty + ty / 4 - ty / 100 + ty / 400 + (int)(2.6 * tm - 0.2) + day) % 7; } //将日期转换为偏移量 inline int toInt() const { int ret = year * 365 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400; days[1] += isLeap(year); for (int i = 0; i < month - 1; ret += days[i++]); days[1] = 28; return ret + day; } //根据给定的偏移量设置当前日期 inline void fromInt(int a) { year = a / 146097 * 400; for (a %= 146097; a >= 365 + isLeap(year); a -= 365 + isLeap(year), year++); days[1] += isLeap(year); for (month = 1; a >= days[month - 1]; a -= days[month - 1], month++); days[1] = 28; day = a + 1; } };
17. kd树
#include <cmath> #include <queue> #include <algorithm> using namespace std; #define sqr(x) (x)*(x) int k,n,idx; //k为维数,n为点数 struct point { int x[K]; bool operator < (const point &u) const { return x[idx]<u.x[idx]; } }po[N]; typedef pair<double,point>tp; priority_queue<tp>nq; struct kdTree { point pt[N<<2]; int son[N<<2]; void build(int l,int r,int rt=1,int dep=0) { if(l>r) return; son[rt]=r-l; son[rt*2]=son[rt*2+1]=-1; idx=dep%k; int mid=(l+r)/2; nth_element(po+l,po+mid,po+r+1); pt[rt]=po[mid]; build(l,mid-1,rt*2,dep+1); build(mid+1,r,rt*2+1,dep+1); } void query(point p,int m,int rt=1,int dep=0) { if(son[rt]==-1) return; tp nd(0,pt[rt]); for(int i=0;i<k;i++) nd.first+=sqr(nd.second.x[i]-p.x[i]); int dim=dep%k,x=rt*2,y=rt*2+1,fg=0; if(p.x[dim]>=pt[rt].x[dim]) swap(x,y); if(~son[x]) query(p,m,x,dep+1); if(nq.size()<m) nq.push(nd),fg=1; else { if(nd.first<nq.top().first) nq.pop(),nq.push(nd); if(sqr(p.x[dim]-pt[rt].x[dim])<nq.top().first) fg=1; } if(~son[y]&&fg) query(p,m,y,dep+1); } }kd;