贴代码
这是一篇代码大杂烩,原来的博客里分成了好多篇发布。这次博客重整,把它们全合成了一篇。请点下面的链接进入阅读。代码较多,请耐心等待。
贴代码—排序算法
马上就要省选了,这几天练习基础算法。排序是基础中的基础,所以先写排序代码。下面的代码基本上用了模板,所以应该是能广泛适用的。(只要重载小于操作符就可以了)当然这里都是最简单的排序算法,放在这里也仅仅是用来备忘。代码巨丑,看之前做好心理准备。
数据产生器
#include <cstdio> #include <ctime> #include <cstdlib> int main() { srand( time( NULL ) ); int n; scanf( "%d" , &n ); FILE* fout = fopen( "sort.in" , "w" ); fprintf( fout , "%d\n" , n ); for( int i = 1 ; i <= n ; ++ i ) { fprintf( fout , "%d\n" , rand() % 100000 ); } fclose( fout ); } |
冒泡排序
template < typename T > void bubSort( T* arr , int st , int ed ) { for( int i = st ; i <= ed ; ++ i ) { for( int j = ed ; j > i ; -- j ) { if ( arr[ j ] < arr[ j - 1 ] ) { T t = arr[ j ]; arr[ j ] = arr[ j - 1 ]; arr[ j - 1 ] = t; } } } } |
选择排序
template < typename T > void selSort( T* arr , int st , int ed ) { for( int i = st ; i <= ed ; ++ i ) { for( int j = i + 1 ; j <= ed ; ++ j ) { if ( arr[ j ] < arr[ i ] ) { T t = arr[ j ]; arr[ j ] = arr[ i ]; arr[ i ] = t; } } } } |
插入排序
template < typename T > void insSort( T* arr , int st , int ed ) { for( int i = st + 1 ; i <= ed ; ++ i ) { int j = i; T cur = arr[ i ]; while ( cur < arr[ j - 1 ] ) { arr[ j ] = arr[ j - 1 ]; -- j; } arr[ j ] = cur; } } |
快速排序
template < typename T > void qSort( T* arr , int st , int ed ) { int i = st , j = ed; T mid = arr[ ( st + ed ) / 2 ]; do { while ( arr[ i ] < mid ) ++ i; while ( mid < arr[ j ] ) -- j; if ( i <= j ) { T t = arr[ i ]; arr[ i ] = arr[ j ]; arr[ j ] = t; ++ i; -- j; } } while ( i <= j ); if ( st < j ) qSort( arr , st , j ); if ( i < ed ) qSort( arr , i , ed ); } |
归并排序,这里写得不好,见谅。
int tmp[ MAX_N + 1 ]; template < typename T > void mergeSort( T* arr , int st , int ed ) { if ( st >= ed ) return; int mid = ( st + ed ) / 2; mergeSort( arr , st , mid ); mergeSort( arr , mid + 1 , ed ); for( int i = st ; i <= ed; ++ i ) tmp[ i ] = arr[ i ]; int h1 = st , h2 = mid + 1 , cur = st; while ( cur <= ed ) { if ( tmp[ h1 ] < tmp[ h2 ] && h1 <= mid || h2 > ed ) { arr[ cur++ ] = tmp[ h1 ++ ]; } else { arr[ cur++ ] = tmp[ h2 ++ ]; } } } |
堆排序,只有上浮下沉的过程,怎么实现排序请查找相关资料。
template< typename T > void sink( T* heap , int len , int k ) { while ( k * 2 <= len ) { int cur = k * 2; if ( cur + 1 <= len && heap[ cur + 1 ] < heap[ cur ] ) ++ cur; if ( heap[ k ] <= heap[ cur ] ) break; T t = heap[ k ]; heap[ k ] = heap[ cur ]; heap[ cur ] = t; k = cur; } } template< typename T > void swim( T* heap , int len , int k ) { while ( k > 1 ) { int cur = k / 2; k = cur * 2; if ( k + 1 <= len && heap[ k + 1 ] < heap[ k ] ) ++ k; if ( heap[ cur ] <= heap [ k ] ) break; T t = heap[ k ]; heap[ k ] = heap[ cur ]; heap[ cur ] = t; k = cur; } } |
线性排序没怎么写,只有一个没有通用性的计数排序,在这里就不贴了。
贴代码—网络流及二分图匹配
今天写了不少,明天还有最后一天,我要把能写的都写写完,准备上战场啦!这里是网络流/匹配。
二分图最大匹配:匈牙利算法
int n , m; bool map[ MAX_N + 1 ][ MAX_M + 1 ]; int lLink[ MAX_N + 1 ] , rLink[ MAX_M + 1 ]; bool vis[ MAX_M + 1 ]; bool extPath( int cur ) { for( int i = 1 ; i <= m ; ++ i ) { if ( !vis[ i ] && map[ cur ][ i ] ){ vis[ i ] = true; if ( rLink[ i ] == 0 || extPath( rLink[ i ] ) ) { lLink[ cur ] = i; rLink[ i ] = cur; return true; } } } return false; } int match() { int ans = 0; for( int i = 1 ; i <= n ; ++ i ) { for( int j = 1 ; j <= m ; ++ j ) { if ( map[ i ][ j ] && rLink[ j ] == 0 ) { lLink[ i ] = j; rLink[ j ] = i; ++ ans; break; } } } for( int i = 1 ; i <= n ; ++ i ) { if ( lLink[ i ] == 0 ) { memset( vis , 0 , sizeof( vis ) ); if ( extPath( i ) ) { ++ ans; } } } return ans; } |
最大流:Dinic算法
const int INF = 10000000; const int MAX_V = 1000 , MAX_E = MAX_V * MAX_V; struct Edge { int to , cap; int bro, next; } edge[ MAX_E * 2 + 1 ]; int eCnt; int hLink[ MAX_V + 1 ]; void _ins( int from , int to , int cap , int bro ) { ++ eCnt; edge[ eCnt ].to = to; edge[ eCnt ].bro = bro; edge[ eCnt ].cap = cap; edge[ eCnt ].next = hLink[ from ]; hLink[ from ] = eCnt; } void ins( int from , int to , int cap ) { _ins( from , to , cap , eCnt + 2 ); _ins( to , from , 0 , eCnt ); } int S , T; int level[ MAX_V + 1 ]; int queue[ MAX_V + 1 ]; bool BFS() { memset( level , 0 , sizeof( level ) ); int head = 0 , tail = 1; queue[ head ] = S; level[ S ] = 1; while( head != tail ) { int cur = queue[ head ++ ]; for( int i = hLink[ cur ]; i ; i = edge[ i ].next ) { if ( edge[ i ].cap == 0 ) continue; int nxt = edge[ i ].to; if ( level[ nxt ] ) continue; level[ nxt ] = level[ cur ] + 1; queue[ tail ++ ] = nxt; } } return level[ T ]; } int stack[ MAX_V + 1 ]; int reach[ MAX_V + 1 ]; int last[ MAX_V + 1 ]; int _maxFlow; void DFS() { int top = 1; stack[ top ] = S; last[ top ] = hLink[ S ]; while( top ) { if ( stack[ top ] != T ) { bool noUse = true; for( int i = last[ top ] ; i ; i = edge[ i ].next ) { if ( edge[ i ].cap ) { last[ top ] = edge[ i ].next; int nxt = edge[ i ].to; if ( level[ nxt ] != level[ stack[ top ] ] + 1 ) continue; stack[ ++ top ] = nxt; reach[ top ] = i; last[ top ] = hLink[ nxt ]; noUse = false; break; } } if ( noUse ) { level[ stack[ top ] ] = - 1; -- top; } } else { int minVol = INF; for( int i = 2 ; i <= top ; ++ i ) { if ( edge[ reach[ i ] ].cap < minVol ) { minVol = edge[ reach[ i ] ].cap; } } for( int i = 2 ; i <= top; ++ i ) { edge[ reach[ i ] ].cap -= minVol; edge[ edge[ reach[ i ] ].bro ].cap += minVol; } _maxFlow += minVol; for( int i = 2 ; i <= top; ++ i ) { if ( edge[ reach[ i ] ].cap == 0 ) { top = i - 1; } } } } } int maxFlow() { _maxFlow = 0; while( BFS() ) { DFS(); } return _maxFlow; } |
其实这里还缺KM和费用流。KM压根不会,费用流就写个最短增广路吧,这里曾经贴过。
重视代码重用是个好习惯。等哪天转ACM了应该会有不少优势。已经开始憧憬ACM了,让我考好点,去趟NOI早点把大学定掉开始ACM吧!
贴代码—数学算法
欧几里德算法、扩展欧几里德算法
void extendEuclid( int a , int b , int& x , int& y ) { if ( b == 0 ) { x = 1 , y = 0; } else { int tx , ty; extendEuclid( b , a % b , tx , ty ); x = ty; y = tx - ( a / b ) * ty; } } int gcd( int a , int b ) { return b ? gcd( b , a % b ) : a; } |
判断是否是素数
#include <iostream> #include <fstream> using namespace std; const int MAX_N = 1000000; bool able[ MAX_N + 1 ]; int pList[ MAX_N + 1 ]; int pCnt; int main() { for( int i = 2 ; i <= MAX_N ; ++ i ) able[ i ] = true; for( int i = 2 ; i <= MAX_N ; ++ i ) { if ( able[ i ] ) pList[ ++pCnt ] = i; for( int j = i + i ; j <= MAX_N ; j += i ) able[ j ] = false; } int n; cin >> n; while ( n >= 0 ) { bool flag = true; for( int i = 1 ; i <= pCnt ; ++ i ) { if ( n < pList[ i ] * pList[ i ] ) break; if ( n % pList[ i ] == 0 ) { flag = false; break; } } cout << ( flag ? "YES\n" : "NO\n" ); cin >> n; } system( "pause" ); } |
高斯消元法
#include <iostream> #include <cmath> using namespace std; const int MAX_N = 100; int n , m; struct Arr { double data[ MAX_N + 2 ]; double& operator[]( int ind ) { return data[ ind ]; } } equ[ MAX_N + 1 ]; void input() { cin >> n; m = n + 1; for( int i = 1 ; i <= n ; ++ i ) { for( int j = 1 ; j <= m ; ++ j ) { cin >> equ[ i ][ j ]; } } } void makeZero( int std , int cur ) { double k = equ[ cur ][ std ] / equ[ std ][ std ]; for( int i = std ; i <= m ; ++ i ) { equ[ cur ][ i ] -= equ[ std ][ i ] * k; } } void process( int cur ) { int maxFrom = cur; for( int i = cur + 1 ; i <= n ; ++ i ) { if ( abs( equ[ maxFrom ][ cur ] ) < abs( equ[ i ][ cur ] ) ) { maxFrom = i; } } if ( maxFrom != cur ) { Arr t = equ[ cur ]; equ[ cur ] = equ[ maxFrom ]; equ[ maxFrom ] = t; } for( int i = cur + 1 ; i <= n ; ++ i ) { makeZero( cur , i ); } } double ans[ MAX_N + 1 ]; void getAns( int cur ) { double rtn = equ[ cur ][ m ]; for( int i = n ; i > cur ; -- i ) { rtn -= equ[ cur ][ i ] * ans[ i ]; } rtn /= equ[ cur ][ cur ]; if ( abs( rtn ) < 1e-6 ) rtn = 0; ans[ cur ] = rtn; } int main() { input(); for( int i = 1 ; i <= n ; ++ i ) { process( i ); } for( int i = n ; i >= 1 ; -- i ) { getAns( i ); } for( int i = 1 ; i <= n ; ++ i ) { cout.precision( 0 ); cout << fixed; cout << ans[ i ] << ( i == n ? "\n" : " " ); } } |
贴代码—凸壳
计算几何都不怎么会,有些知道的从来没写过。唯一会的只有这个凸壳了。这是USACO 5.1 Fencing the Cows的代码,算法是Graham扫描法。
#include <iostream> #include <fstream> #include <cmath> using namespace std; ifstream fin( "fc.in" ); ofstream fout( "fc.out" ); struct Point { double x , y; }; inline double dis( Point a , Point b ) { return sqrt( ( a .x - b.x ) * ( a .x - b.x ) + ( a .y - b.y ) * ( a .y - b.y ) ); } Point operator- ( Point a , Point b ) { Point rtn; rtn.x = a.x - b.x; rtn.y = a.y - b.y; return rtn; } double crossProduct( Point a , Point b ) { return a.x * b.y - b.x * a.y; } Point pStd; bool operator<( Point a, Point b ) { return crossProduct( a - pStd , b - pStd ) > 0; } template< typename T >void qSort( T* arr , int st , int ed ) { int i = st , j = ed; T mid = arr[ ( st + ed ) / 2 ]; while( i <= j ) { while( arr[ i ] < mid ) ++ i; while( mid < arr[ j ] ) -- j; if ( i <= j ) { T t = arr[ i ]; arr[ i ] = arr[ j ]; arr[ j ] = t; ++ i; -- j; } } while( i <= j ); if ( st < j ) qSort( arr , st , j ); if ( i < ed ) qSort( arr , i , ed ); } const int MAX_N = 10000; Point points[ MAX_N + 2 ]; int n; Point stack[ MAX_N + 2 ]; int main() { fin >> n; fin >> points[ 1 ].x >> points[ 1 ].y; for( int i = 2 ; i <= n ; ++ i ) { fin >> points[ i ].x >> points[ i ].y; if ( ( points[ i ].x < points[ 1 ].x ) || ( points[ i ].x == points[ 1 ].x && ( points[ i ].y < points[ 1 ].y ) ) ) { Point t = points[ 1 ]; points[ 1 ] = points[ i ]; points[ i ] = t; } } pStd = points[ 1 ]; qSort( points , 2 , n ); points[ ++ n ] = points[ 1 ]; int top = 0; stack[ ++ top ] = points[ 1 ]; stack[ ++ top ] = points[ 2 ]; /* for( int i = 1 ; i <= n ; ++ i ) { fout << points[ i ].x << " " << points[ i ].y << endl; } */ for( int i = 3 ; i <= n ; ++ i ) { while( top >= 2 && crossProduct( stack[ top ] - stack[ top - 1 ] , points[ i ] - stack[ top - 1 ] ) < 0 ) { -- top; } stack[ ++ top ] = points[ i ]; } double ans = 0; for( int i = 2 ; i <= top ; ++ i ) { ans += dis( stack[ i ] , stack[ i - 1 ] ); } fout.precision( 2 ); fout << fixed; fout << ans << endl; fin.close(); fout.close(); } |
贴代码—KMP
本来应该是个字符串大杂烩的,可惜不会扩展KMP、自动机、后缀数组这些强大的东西,弱弱地贴个KMP,供大家鄙视。
<pre lang="cpp" colla="-"> #include <iostream> #include <string> using namespace std; string mod , str; const int MAX_N = 1000000; int n , m; int next[ MAX_N + 1 ]; void getNext() { int i = 1 , j = 0; while( i <= m ) { if ( j == 0 || mod[ i ] == mod[ j ] ) { ++ i; ++ j; if ( mod[ i ] == mod[ j ] ) { next[ i ] = next[ j ]; } else { next[ i ] = j; } } else { j = next[ j ]; } } } string::size_type pos( int i ) { int j = 1; while( i <= n && j <= m ) { if ( str[ i ] == mod[ j ] || j == 0 ) { ++ i; ++ j; } else { j = next[ j ]; } } if ( j > m ) { return i - j + 1; } else { return string::npos; } } int main() { cout << "Knuth-Morris-Pratt Algorithm Test" << endl; cout << "Input : String Mod_String Starting_Pos" << endl; cin >> str >> mod; n = str.length(); m = mod.length(); str = " " + str; mod = " " + mod; getNext(); int oriPos; cin >> oriPos; cout << "K-M-P Algorithm return = " << pos( oriPos ) << endl; cout << "C++ Class String return = " << str.find( mod.substr( 1 , m ) , oriPos ) << endl; system( "pause" ); } |
贴代码—数据结构
明天就要出发了,把这里剩下的贴贴完吧。接下来是数据结构,常用的并查集、堆以及平衡树。
堆,好像是是小根堆。 <pre lang="cpp" colla="-"> template< typename T >class Heap { private: static const int MAX_N = 1000000; T data[ MAX_N + 1 ]; int n; void swim( int cur ) { while( cur > 1 ) { int fat = cur / 2; cur = fat * 2; if ( cur < n && data[ cur + 1 ] < data[ cur ] ) ++ cur; if ( data[ cur ] < data[ fat ] ) { T t = data[ cur ]; data[ cur ] = data[ fat ]; data[ fat ] = t; cur = fat; } else { break; } } } void sink( int cur ) { while( cur <= n ) { int fat = cur; cur *= 2; if ( cur < n && data[ cur + 1 ] < data[ cur ] ) ++ cur; if ( cur <= n && data[ cur ] < data[ fat ] ) { T t = data[ cur ]; data[ cur ] = data[ fat ]; data[ fat ] = t; } else { break; } } } public: Heap() { n = 0; } void ins( T node ) { data[ ++ n ] = node; swim( n ); } T getMin() { assert( n ); return data[ 1 ]; } void delMin() { data[ 1 ] = data[ n -- ]; sink( 1 ); } void printAll() { for( int i = 1 ; i <= n ; ++ i ) { cout << data[ i ] << " "; } cout << endl; } }; |
并查集
class DisjointSet { private: static const int MAX_N = 100000; int fat[ MAX_N + 1 ]; int stack[ MAX_N + 1 ]; public: DisjointSet() { for( int i = 1 ; i <= MAX_N ; ++ i ) { fat[ i ] = i; } } int findSet( int cur ) { int top = 1; stack[ top ] = cur; while( stack[ top ] != fat[ stack[ top ] ] ) { stack[ top + 1 ] = fat[ stack[ top ] ]; ++ top; } int rtn = stack[ top ]; for( int i = 1 ; i <= top ; ++ i ) fat[ stack[ i ] ] = rtn; return rtn; } bool isSame( int a , int b ) { return findSet( a ) == findSet( b ); } void unionSet( int a , int b ) { int fatA = findSet( a ) , fatB = findSet( b ); fat[ fatA ] = fatB; } }; |
平衡树,Treap,见这里。
贴代码—基础图论算法
这是贴代码系列的最后一部分,也是最最丑的一部分。因为放在这里仅供备忘,所以神牛们将就点吧……
图的点数、边数定义、邻接表的插入。
const int INF = 1000000000; const int MAX_N = 100, MAX_M = 100000; int n , m; struct Edge { int tar , weight; int next; } edge[ MAX_M + 1 ]; int lHead[ MAX_N + 1 ]; int eCnt; void ins( int src , int tar , int wei ) { ++ eCnt; edge[ eCnt ].next = lHead[ src ]; lHead[ src ] = eCnt; edge[ eCnt ].tar = tar; edge[ eCnt ].weight = wei; } |
图的遍历,深度优先及广度优先搜索
void bfs( int src ) { queue[ head ] = src; vis[ src ] = true; while ( head != tail ) { int cur = queue[ head ++ ]; fout << "BFS " << cur << endl; for( int i = lHead[ cur ] ; i ; i = edge[ i ].next ) { if ( !vis[ edge[ i ].tar ] ) { vis[ edge[ i ].tar ] = true; queue[ tail ++ ] = edge[ i ].tar; } } } } void dfs( int cur ) { vis[ cur ] = true; fout << "DFS " << cur << endl; for( int i = lHead[ cur ] ; i ; i = edge[ i ].next ) { if ( !vis[ edge[ i ].tar ] ) { dfs( edge[ i ].tar ); } } } |
最小生成树Prim算法。(突然发现少了Kruskal算法,算了就不写了吧)
int dis[ MAX_N + 1 ]; int prim( int src ) { int rtn = 0; for( int i = 1 ; i <= n ; ++ i ) dis[ i ] = INF; dis[ src ] = 0; for( int i = 1 ; i <= n ; ++ i ) { int minID , min = INF; for( int j = 1 ; j <= n ; ++ j ) { if ( dis[ j ] < min && !vis[ j ] ) { min = dis[ j ]; minID = j; } } vis[ minID ] = true; rtn += dis[ minID ]; for( int j = lHead[ minID ] ; j ; j = edge[ j ].next ) { if ( edge[ j ].weight < dis[ edge[ j ].tar ] ) { dis[ edge[ j ].tar ] = edge[ j ].weight; } } } return rtn; } |
常用的两种最短路算法,Dijkstra与SPFA。
int dis[ MAX_N + 1 ]; void dijkstra( int src ) { for( int i = 1 ; i <= n ; ++ i ) dis[ i ] = INF; dis[ src ] = 0; for( int i = 1 ; i <= n ; ++ i ) { int minID , min = INF; for( int j = 1 ; j <= n ; ++ j ) { if ( dis[ j ] < min && !vis[ j ] ) { min = dis[ j ]; minID = j; } } vis[ minID ] = true; for( int j = lHead[ minID ] ; j ; j = edge[ j ].next ) { if ( dis[ minID ] + edge[ j ].weight < dis[ edge[ j ].tar ] ) { dis[ edge[ j ].tar ] = dis[ minID ] + edge[ j ].weight; } } } } void spfa( int src ) { queue[ head = 0 ] = src; tail = 1; vis[ src ] = true; for( int i = 1 ; i <= n ; ++ i ) dis[ i ] = INF; dis[ src ] = 0; while ( head != tail ) { int cur = queue[ head ++ ]; head %= MAX_N; vis[ cur ] = false; for( int i = lHead[ cur ]; i ; i = edge[ i ].next ) { if ( dis[ cur ] + edge[ i ].weight < dis[ edge[ i ].tar ] ) { dis[ edge[ i ].tar ] = dis[ cur ] + edge[ i ].weight; if ( !vis[ edge[ i ].tar ] ) { vis[ edge[ i ].tar ] = true; queue[ tail++ ] = edge[ i ].tar; tail %= MAX_N; } } } } } |
拓扑排序
void topoSort() { for( int i = 1 ; i <= eCnt ; ++ i ) ++d[ edge[ i ].tar ]; head = tail = 0; for( int i = 1 ; i <= n ; ++ i ) { if ( d[ i ] == 0 ) { queue[ tail++ ] = i; } } while ( head != tail ) { int cur = queue[ head++ ]; fout << cur << " "; for( int i = lHead[ cur ]; i ; i = edge[ i ].next ) { if ( -- d[ edge[ i ].tar ] == 0 ) queue[ tail ++ ] = edge[ i ].tar; } } } |
