序号 | 算法 |
---|---|
① | SPFA |
② | 并查集 |
③ | 最小生成树 |
④ | 拓扑排序 |
⑤ | 堆 |
⑥ | 字典树 |
N | 懒得加了 |
1. SPFA
题目链接
题目描述
输入的第一行是四个整数,代表站点个数 n 和线路条数 m ,出发点 x 和 目的地 y 。 第 2 到第 (m + 1) 行,每行三个整数 u, v, w 代表存在一条从 u 出发到达 v 的线路,边权为 w。 输出从 x 到 y 点的最短路径。
code
#include <bits/stdc++.h> using namespace std ; int n , m , x , y ; int tot ; int head[1000005] ; int dis[1000005] ; int b[1000005] ; struct node { int u , v , w , next ; } e[1000005] ; void add ( int u , int v, int w ) { tot++ ; e[tot].u = u ; e[tot].v = v ; e[tot].w = w ; e[tot].next = head[u] ; head[u] = tot ; } void spfa ( int s ) { queue < int > q ; for ( int i = 1 ; i <= n ; i++ ) { dis[i] = 1E15 ; } b[s] = 1 ; dis[s] = 0 ; q.push ( s ) ; while ( ! q.empty( ) ) { int u = q.front( ) ; q.pop( ) ; b[u] = 0 ; for ( int i = 1 ; i != 0 ; i = e[i].next ) { int v = e[i].v ; int w = e[i].w ; if ( dis[u] + w < dis[v] ) { dis[v] = dis[u] + w ; if ( b[v] == 0 ) { b[v] = 1 ; q.push ( v ) ; } } } } } int main ( ) { cin >> n >> m >> x >> y ; for ( int i = 1 ; i <= m ; i++ ) { int u , v , w ; cin >> u >> v >> w ; add ( u , v , w ) ; } spfa( x ) ; cout << dis[y] ; return 0 ; }
2. 并查集
题目链接
PS:注意要将 fa 数组指向自己
code
#include <bits/stdc++.h> using namespace std ; int n , m ; int fa[10005] ; int find ( int x ) { if ( fa[x] == x ) { return x ; } return fa[x] = find ( fa[x] ) ; } int main ( ) { cin >> n >> m ; for ( int i = 1 ; i <= n ; i++ ) { fa[i] = i ; } for ( int i = 1 ; i <= m ; i++ ) { int z , x , y ; cin >> z >> x >> y ; x = find ( x ) ; y = find ( y ) ; if ( z == 1 ) { fa[x] = y; } else if ( z == 2 ) { if ( x == y ) { cout << "Y" << endl ; } else { cout << "N" << endl ; } } } return 0 ; }
3. 最小生成树
题目链接
code
#include <bits/stdc++.h> using namespace std ; int n , m ; int tot , cnt , sum ; int fa[500005] ; struct node { int u , v , w , next ; } e[400005] ; bool cmp ( node x , node y ) { return x.w < y.w ; } int find ( int x ) { if ( fa[x] == x ) { return x ; } return fa[x] = find ( fa[x] ) ; } int main ( ) { cin >> n >> m ; for ( int i = 1 ; i <= n ; i++ ) { fa[i] = i ; } for ( int i = 1 ; i <= m ; i++ ) { cin >> e[i].u >> e[i].v >> e[i].w ; } sort ( e + 1 , e + m + 1 , cmp ) ; for ( int i = 1 ; i <= m ; i++ ) { int u = e[i].u ; int v = e[i].v ; int w = e[i].w ; u = find ( u ) ; v = find ( v ) ; if ( u != v ) { fa[u] = v ; cnt++ ; sum += w ; } if ( cnt == n - 1 ) { cout << sum ; return 0 ; } } cout << "orz" ; return 0 ; }
4. 拓扑排序
题目链接
code
#include <bits/stdc++.h> using namespace std ; int n , m ; int ans ; int head[5005] ; int ind[5005] ; int sum[5005] ; struct node { int u , v , next ; } e[500005] ; void topsort ( ) { queue<int> q ; for ( int i = 1 ; i <= n ; i++ ) { if ( ind[i] == 0 ) { q.push( i ) ; sum[i] = 1 ; } } while ( !q.empty() ) { int u = q.front() ; q.pop(); for ( int i = head[u] ; i != 0 ; i = e[i].next ) { int v = e[i].v ; ind[v]--; sum[v] += sum[u] ; // 继承上一个结点 sum[v] %= 80112002 ; if ( ind[v] == 0 ) { q.push( v ) ; } } } } int main() { cin >> n >> m ; for ( int i = 1 ; i <= m ; i++ ) { int u , v ; cin >> u >> v ; e[i].u = u ; e[i].v = v ; e[i].next = head[u] ; head[u] = i ; ind[v]++ ; // 出度 +1 } topsort(); for ( int i = 1 ; i <= n ; i++ ) { if ( head[i] == 0 ) { ans += sum[i] ; ans %= 80112002 ; // 提前模 防止爆数组 } } cout << ans ; return 0 ; }
5. 堆
题目模板
code
#include <bits/stdc++.h> using namespace std ; priority_queue < int , vector < int > , greater < int > > q ; int main ( ) { int n ; cin >> n ; for ( int i = 1 ; i <= n ; i++ ) { int op ; cin >> op ; if ( op == 1 ) { int x ; cin >> x ; q.push ( x ) ; } if ( op == 2 ) { cout << q.top ( ) << endl ; } if ( op == 3 ) { q.pop ( ) ; } } return 0 ; }
6. 字典树
题目链接
code
#include<bits/stdc++.h> using namespace std; int t; int cnt; int tri[4000005][65]; long long ans[4000005]; int bh( char a ){ if( a >= 'A' && a <= 'Z' ) { return a - 'A'; } else if( a >= 'a' && a <= 'z' ) { return a - 'a' + 26; } else if( a >= '0' && a <= '9' ) { return a - '0' + 52; } } void build( string a ){ int len = a.size(); int root = 0; for( int i = 0 ; i < len ; i++ ) { int x = bh( a[i] ); if( !tri[root][x] ) { ++cnt , tri[root][x] = cnt; root = cnt; } else { root = tri[root][x]; } ans[root]++; } } int query( string a ){ int len = a.size(); int root = 0; for( int i = 0 ; i < len ; i++ ) { int x = bh( a[i] ); if( !tri[root][x] ) return 0; else root = tri[root][x]; } return ans[root]; } void qk(){ for( int i = 0 ; i <= cnt ; i++ ) { for( int j = 0 ; j <= 64 ; j++ ) { tri[i][j] = 0; } } for( int i = 1 ; i <= cnt ; i++ ) { ans[i] = 0; } cnt = 0; } void work(){ qk(); int n , q; cin >> n >> q; for( int i = 1 ; i <= n ; i++ ) { string a; cin >> a; build( a ); } for( int i = 1 ; i <= q ; i++ ) { string a; cin >> a; cout << query( a ) << endl; } } int main(){ cin >> t; for( int i = 1 ; i <= t ; i++ ) { work(); } return 0; }二分查找
元素最后出现位置 等于upper_bound #include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,i,x,ans; int a[1000005]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) { scanf("%d",&x); int li=1,ri=n,mi; while(li<=ri) { mi=li+(ri-li)/2; if(x<a[mid]) ri=mi-1; else {ans=mi;li=mi+1;} } if(a[ans]==x) printf("%d ",ans); else printf("-1 "); } return 0; } 元素最先出现位置 等于lower_bound #include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,i,x,ans; int a[1000010]; int main() { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=m;i++) { scanf("%d",&x); int li=1,ri=n,mi; while(li<=ri) { mi=li+(ri-li)/2; if(x<=a[mi]) {ans=mi;ri=mi-1;} else li=mi+1; } if(a[ans]==x) printf("%d ",ans); else printf("-1 "); } return 0; }hash插入函数
void insert() { int hx=1; for(int i=0;i<re.size();i++) { hx=(hx*base+re[i])%mod; } for(int i=0;i<s[hx].size();i++) { if(s[hx][i]==re) return; } ans++; s[hx].push_back(re); }快速幂
long long pow(long long x,long long y,long long m) { long long re=1; while(y>=1) { if(y&1) re=re*x%m; x=x*x%m; y>>=1; } return re; }线段树
inline void build(int i,int l,int r){//递归建树 tree[i].l=l;tree[i].r=r; if(l==r){//如果这个节点是叶子节点 tree[i].sum=input[l]; return ; } int mid=(l+r)>>1; build(i*2,l,mid);//分别构造左子树和右子树 build(i*2+1,mid+1,r); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;//刚才我们发现的性质return ; } 例子:求和 inline int search(int i,int l,int r){ if(tree[i].l>=l && tree[i].r<=r)//如果这个区间被完全包括在目标区间里面,直接返回这个区间的值 return tree[i].sum; if(tree[i].r<l || tree[i].l>r) return 0;//如果这个区间和目标区间毫不相干,返回0 int s=0; if(tree[i*2].r>=l) s+=search(i*2,l,r);//如果这个区间的左儿子和目标区间又交集,那么搜索左儿子 if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r);//如果这个区间的右儿子和目标区间又交集,那么搜索右儿子 return s; }区间修改
inline void add(int i,int l,int r,int k){ if(tree[i].l>=l && tree[i].r<=r){//如果这个区间被完全包括在目标区间里面,讲这个区间标记k tree[i].sum+=k; return ; } if(tree[i*2].r>=l) add(i*2,l,r,k); if(tree[i*2+1].l<=r) add(i*2+1,l,r,k); } //单点查询 void search(int i,int dis){ ans+=tree[i].sum;//一路加起来 if(tree[i].l==tree[i].r) return ; if(dis<=tree[i*2].r) search(i*2,dis); if(dis>=tree[i*2+1].l) search(i*2+1,dis); }树状数组(简单版线段树)
int lowbit(int x) { return x&(-x); }//求二进制最低位1 /*void add(int u,int v)//u表示位置,v表示加数 { for(int i=u;i<=n;i+=lowbit(i)) { c[i]+=v; } return; } void build() { for(int i=1;i<=n;i++) { add(i,a[i]); } return; }O(nlogn)build*/ void build() { for(int i=1;i<=n;i++) { c[i]+=a[i]; int fa=i+lowbit(i); if(fa<=n) { c[fa]+=c[i]; } } return; }//O(n)build 单点修改 void change(int u,int v)//u is address,v is the number that add. { for(int i=u;i<=n;i+=lowbit(i)) { c[i]+=v; } } int getsum(int m)//前缀和 { int ans=0; for(int i=m;i>0;i-=lowbit(i)) { ans+=c[i]; } return ans; }
评论列表