暫存一些模板
很久以前記得一些模板,一些自己寫的,一些可能是別的地方複製下來的,意義不大但是對以後的整理可能有幫助就先暫存在這了,侵刪
一、博弈
//1.巴什博弈(Bash Game)
//一堆n個物品,兩個人輪流從中取出1~m個,最後取光者勝(不能繼續取的人輸)。
//同餘定理:n=k*(m+1)+r,先者拿走r個,那麼後者無論拿走1 m個先者只要的數目使和為m+1,那麼先手必贏。反之若n=k*(m+1),那麼先手無論怎樣都會輸。
bool bashGame(int n,int m){
if (n % (m + 1)) return false;
else return true;
}
//2.斐波那契博弈(Fibonacci Nim Game)
//一堆石子有n個,兩人輪流取,先取者第一次可以去任意多個,但是不能取完,以後每次取的石子數不能超過上次取子數的2倍。取完者勝。
//同樣是一個規律:先手勝當且僅當n不是斐波那契數。
bool fibonacciGame(int n){
f[0] = f[1] = 1;
for (int i = 0; f[i - 1] < n; i++)
{
f[i] = f[i - 1] + f[i - 2];
if (f[i] == n) return true;
}
return false;
}
//3.威佐夫博弈(Wythoff Game)
//有兩堆各若干物品,兩個人輪流從任意一堆中至少取出一個或者從兩堆中取出同樣多的物品,規定每次至少取一個,至多不限,最後取光者勝。
//這裡的必輸局勢:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
//從這些必輸局勢可以發現,每組的第一個是前面沒有出現的最小正整數,ak=[k*(1+sqrt(5)/2], bk=ak+k, k=0,1,2,3...。
bool wythoffGame(int a,int b){
double r = (sqrt(5) + 1) / 2;
int d = abs(a - b) * r;
if (d != min(a, b)) return true;
else false;
}
//4.尼姆博弈(Nim Game)
//有n堆物品,兩人輪流取,每次取某堆中不少於1個,最後取完者勝。
//通過驗證所有的堆數量累^後只要為0就都是必輸局勢,所以我們就只要記住這個規則:
//將n堆物品數量全部異或後結果為0先手必敗,否則必勝。
bool NimGame(int arr[]){
int res = 0;
for (int i = 1; i <= n; i++)
res ^= arr[i];
if (res) return true;
else return false;
}
//5.SG函式
//待續
二、最小生成樹
//Prim模板
//題目連結 : http://poj.org/problem?id=1287
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 100 + 10;
const int INF = 1<<30;
struct Node{
int v,w;
Node (){}
Node (int v,int w):v(v),w(w){}
bool operator < (const Node&rhs ) const {
return rhs.w < w;
}
};
int n,d[maxn];
bool vis[maxn];
int Map[maxn][maxn];
void init(){
for(int i = 0; i < maxn; i++)vis[i] = false;
for(int i = 0; i < maxn; i++)d[i] = INF;
}
int Prim(int s){
priority_queue<Node>q;
q.push(Node(s,0));
int ans = 0;
while(!q.empty()){
Node Now = q.top(); q.pop();
int v = Now.v;
if(vis[v]) continue;
ans += Now.w;
vis[v] = true;
for(int i = 1; i <= n; i++){
int w2 = Map[v][i];
if(!vis[i] && d[i] > w2){
d[i] = w2;
q.push(Node(i,d[i]));
}
}
}
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
int m,a,b,c;
while(~scanf("%d",&n)&&n){
scanf("%d",&m);
init();
for(int i = 1; i <= n; i++){
Map[i][i] = INF;
for(int j = 1; j < i; j++)Map[i][j] = Map[j][i] = INF;
}
for(int i = 0; i < m; i++){
scanf("%d%d%d",&a,&b,&c);
if(c < Map[a][b])Map[a][b] = Map[b][a] = c; //注意重邊,取小的
}
printf("%d\n",Prim(1));
}
return 0;
}
//kruskal模板
//題目連結 : http://poj.org/problem?id=1287
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
int Fa[maxn],Rank[maxn];
void init(){
for(int i = 0; i <= maxn; i++)Fa[i] = i;
for(int i = 0; i <= maxn; i++)Rank[i] = 1;
}
int Find(int v){
return Fa[v] == v ? v : Fa[v] = Find(Fa[v]);
}
void Union(int x, int y){
int fx = Find(x);
int fy = Find(y);
if (fx == fy)return;
if (Rank[fx] < Rank[fy])
Fa[fx] = fy;
else{
Fa[fy] = fx;
if (Rank[fx] == Rank[fy])Rank[fy]++;
}
}
struct Edge{
int u,v,w;
Edge(){}
Edge(int u,int v,int w):u(u),v(v),w(w){}
}edge[maxn*2];
int cmp(const void *a,const void *b){
Edge *aa = (Edge*)a;
Edge *bb = (Edge*)b;
return aa->w > bb->w ? 1 : -1; //降序
}
int krusal(int n,int m){
qsort(edge,m,sizeof(edge[0]),cmp);
int ans = 0;
int cnt = 0;
for(int i = 0; i < m; i++){
int u = edge[i].u;
int v = edge[i].v;
if(Find(u) != Find(v)){
Union(u,v);
cnt++;
ans += edge[i].w;
}
if(cnt == n-1)break;
}
return ans;
}
int main(){
//freopen("in.txt","r",stdin);
int n,m;
while(~scanf("%d",&n)&&n){
scanf("%d",&m);
init();
for(int i = 0; i < m; i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); //注意這題有重邊但是沒事
printf("%d\n",krusal(n,m));
}
return 0;
}
三、計算幾何
//計算幾何
struct node {
double x; // 橫座標
double y; // 縱座標
};
//1.向量運算
typedef node Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }
double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 向量點乘
double Length(Vector A) { return sqrt(Dot(A, A)); } // 向量模長
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } // 向量之間夾角
double Cross(Vector A, Vector B) { // 叉積計算 公式
return A.x*B.y - A.y*B.x;
}
Vector Rotate(Vector A, double rad) // 向量旋轉 公式 {
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}
Point getLineIntersection(Point P, Vector v, Point Q, Vector w) { // 兩直線交點t1 t2計算公式
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w); // 求得是橫座標
return P + v*t; // 返回一個點
}
//2.多邊形面積
node G[maxn];
int n;
double Cross(node a, node b) { // 叉積計算
return a.x*b.y - a.y*b.x;
}
int main()
{
while (scanf("%d", &n) != EOF && n) {
for (int i = 0; i < n; i++)
scanf("%lf %lf", &G[i].x, &G[i].y);
double sum = 0;
G[n].x = G[0].x;
G[n].y = G[0].y;
for (int i = 0; i < n; i++) {
sum += Cross(G[i], G[i + 1]);
}
// 或者
//for (int i = 0; i < n; i++) {
//sum += fun(G[i], G[(i + 1)% n]);
//}
sum = sum / 2.0;
printf("%.1f\n", sum);
}
return 0;
}
//3.判斷線段相交
node P[35][105];
double Cross_Prouct(node A,node B,node C) { // 計算BA叉乘CA
return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);
}
bool Intersect(node A,node B,node C,node D) { // 通過叉乘判斷線段是否相交;
if(min(A.x,B.x)<=max(C.x,D.x)&& // 快速排斥實驗;
min(C.x,D.x)<=max(A.x,B.x)&&
min(A.y,B.y)<=max(C.y,D.y)&&
min(C.y,D.y)<=max(A.y,B.y)&&
Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&& // 跨立實驗;
Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0) // 叉乘異號表示在兩側;
return true;
else return false;
}
//4.三角形外心
Point circumcenter(const Point &a, const Point &b, const Point &c) { //返回三角形的外心
Point ret;
double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;
double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;
double d = a1*b2 - a2*b1;
ret.x = a.x + (c1*b2 - c2*b1) / d;
ret.y = a.y + (a1*c2 - a2*c1) / d;
return ret;
}
四、並查集
//並查集
int father[maxn]; // 儲存i的father父節點
void makeSet() {
for (int i = 0; i < maxn; i++)
father[i] = i;
}
int findRoot(int x) { // 迭代找根節點
int root = x; // 根節點
while (root != father[root]) { // 尋找根節點
root = father[root];
}
while (x != root) {
int tmp = father[x];
father[x] = root; // 根節點賦值 (路徑上的每個節點都可以直接連線到根上)
x = tmp;
}
return root;
}
void Union(int x, int y) { // 將x所在的集合和y所在的集合整合起來形成一個集合。
int a, b;
a = findRoot(x);
b = findRoot(y);
father[a] = b; // y連在x的根節點上 或father[b] = a為x連在y的根節點上;
}
五、矩陣運算
六、DP問題
揹包
最長公共子序列
七、數論
歐幾里得及擴充
#include<iostream>
using namespace std;
//歐幾里得演算法:
int gcd(int a, int b)
{
if (a < b) swap(a, b);
return b == 0 ? a : gcd(b, a % b);
}
//擴充歐幾里得:
//既可以求出最大公約數,還可以順帶求解出使得: a* x + b * y = gcd 的特解 x 和 y
//最後狀態為x=1,y=0,以此遞推求出最初狀態x與y
//前狀態x1,y1與後狀態x2,y2關係公式
//x1 = y2
//y1 = x2 – a / b * y2
int exgcd(int a, int b, int& x1, int& y1)
{
if (!b)
{
x1 = 1, y1 = 0;
return a;
}
int x2, y2;
int d = exgcd(b, a % b, x2, y2);
x1 = y2, y1 = x2 - (a / b) * y2;
return d;
}
int main()
{
int a, b, x, y;
while (cin >> a >> b >> x >> y) {
cout << exgcd(a, b, x, y) << endl;
cout << x << ' ' << y << endl;
}
return 0;
}
快速冪 尤拉函式及降冪
#include<iostream>
#include<math.h>
using namespace std;
typedef long long ll;
char b[1000010];
//快速冪演算法(對mod取模)
ll fastPower(ll base, ll power,ll mod)
{
ll ans = 1;
base %= mod;
while (power > 0) {
if (power & 1) {//指數為奇數,先乘
ans = ans * base % mod;
}
power >>= 1;//指數取半
base = (base * base) % mod;//基數平方
}
return ans;
}
//尤拉函式phi(n),表示小於等於n中與n互質的數的數量
//尤拉定理 對於任意互素的 a 和 n,有 a^phi(n)≡1(mod n)
// 得到通式:phi(n) = n * (1 - 1 / p1) * (1 - 1 / p2) *...* (1 - 1 / pn);p為n的所有質因數
ll euler_phi(ll n)
{
ll ans = n;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0)//i是n的因數
{
ans -= ans / i;//通式公式
while (n % i == 0)
n /= i;//消去i因子
}
}
if (n > 1) ans -= ans / n;//判斷是否還剩下因子
return ans;
}
//尤拉降冪 a^b mod c = a^(b mod phi(c) + phi(c)) mod c;
ll eularDropPow(ll base, char pow[], ll mod)
{
ll phi = euler_phi(mod);//得到尤拉函式值(phi(mod))
ll newPow = 0;
for (ll i = 0, len = strlen(pow); i < len; i++) {
newPow = (newPow * 10 + pow[i] - '0') % phi;//每一次迴圈都取模防止溢位;
}
newPow += phi;//根據降冪公式,加上phi(mod),得到最終的新指數
return newPow;//返回降冪後的冪指數
}
int main()
{
ll a, c;
while (cin >> a >> b >> c) {
ll newPow = eularDropPow(a, b, c);
cout << fastPower(a, newPow, c) << endl;
}
return 0;
}
組合數學等等
爭取寒假全都搞出來再系統地發一篇吧,不過模板還是自己整理的有用,現在的比賽也越來越不需要模板了,更多的作用可能在於加深印象,輔助做題吧。。
相關文章
- 暫存一下線段樹模板
- STM32暫存器操作、模板構建
- 暫存
- CS 暫存器 和 IP 暫存器
- 暫存器
- PC暫存器
- 暫存器定址和暫存器間接定址的區別
- Git清空暫存區Git
- 為什麼Modbus的只讀暫存器被稱為“輸入暫存器(Input Registers)”而不是“輸出暫存器”
- 【STM32】【暫存器】暫存器位讀寫方式配置系統時鐘
- CS、IP和PC暫存器
- Git暫存區深入理解Git
- Git工作區和暫存區Git
- CPU 中通用暫存器的作用
- 新手分享_再談FS暫存器
- 暫存器指定為寫0或者1
- STM32 GPIO 暫存器的配置
- 10.1 除錯事件讀取暫存器除錯事件
- 6.常見暫存器和指令
- 程式設計中暫存器的使用程式設計
- 第五章:通用暫存器是()。
- iOS彙編基礎(二)暫存器iOS
- Java讀取暫存器資料的方法Java
- 一文搞懂 ARM 64 系列: 暫存器
- 程式分析與優化 - 8 暫存器分配優化
- 基於暫存器呼叫的軟體加速
- 【C/C++】 C++暫存器優化C++優化
- Git刪除暫存區的指定檔案Git
- 【STC8H】STC8系列專有的特殊的暫存器位——PW_2暫存器的最高位 EAXFR
- ps暫存檔已滿去哪清理 ps顯示暫存檔已滿怎麼刪除更改資料夾位置
- 模板字串的一些用法小記字串
- 函式呼叫暫存器及棧幀結構函式
- CPU中跟蹤後繼指令地址的暫存器
- Mac版Sourcetree暫存程式碼和取出程式碼Mac
- 暫存器,觸發器,三極體小結觸發器
- Git-命令列-使用 git stash 暫存程式碼Git命令列
- Intel 8086微處理器暫存器結構Intel
- Git檢視暫存區index檔案內容GitIndex