ACM基本算法板子记录

18 篇文章 0 订阅
2 篇文章 0 订阅

头文件

#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define pii pair<int,int>
#define ll long long
#define inf 1e9
using namespace std;
const int N = 2e5+10;

快读

template <class T>
inline void read(T &res)
{
	char c;
	T flag = 1;
	while ((c = getchar()) < '0' || c > '9')
		if (c == '-')
			flag = -1;
	res = c - '0';
	while ((c = getchar()) >= '0' && c <= '9')
		res = res * 10 + c - '0';
	res *= flag;
}

素数筛法

埃筛
int vis[N];
int prime[N];
void Ai_init(int x){
	for(int i = 2;i <= N;i++){
		if(!vis[i]){
			prime[++prime[0]] = i;//prime[i]表示素数个数
			int l = 2;
			while(l*i <= N){
                vis[l*i] = 1;
                l++;
			}
		}
	}
}
欧筛
int vis[N];
int prime[N];
void Ou_init(int x){
	for(int i = 2;i<=N/2;i++){
        if(!vis[i])prime[++prime[0]] = i;
        for(int j = 1;j <= prime[0]&&j*i<=N;j++){
            vis[i*prime[j]] = 1;
            if(i%prime[j]==0)break;
        }
    }
}

快速幂

ll binpow(ll a, ll b, ll c){
	ll res = 1;'
	while(b){
		if(b&1)res = res*a%c;
		a = (a*a)%c;
		b >>= 1;
	}
	return res;
}

GCD and LCM

int gcd(int a, int b){
	int c = a%b;
    while(c){
        a = b;
        b = c;
        c = a % b;
    }
    return b;
}
int lcm(int a, int b){
    return a*b/gcd(a,b);
}

DP板子

01 01 01 背包
int n, m, k;
int v[N], w[N], dp[N];
void solve()
{
	cin>>n>>k;
	for(int i = 1;i <= n;i++)cin>>v[i]>>w[i];
	for(int i = 1;i <= n;i++){
		for(int j = k;j >= v[i];j--){
			dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
		}
	}cout<<dp[k]<<endl;

}
完全背包
int v[N], w[N], dp[N];
void solve()
{
	cin>>n>>k;
	for(int i = 1;i <= n;i++)cin>>v[i]>>w[i];
	for(int i = 1;i <= n;i++){
		for(int j = v[i];j <= k;j++){
			dp[j] = max(dp[j],dp[j-v[i]]+w[i]);
		}
	}
	cout<<dp[k]<<endl;

}
多重背包
朴素
void solve()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++)cin>>v[i]>>w[i]>>s[i];
	for(int i = 1;i <= n;i++){
		for(int j = 0;j <= m;j++){
			for(int k = 0;k <= s[i]&&k*v[i]<=j;k++){
				dp[i][j] = max(dp[i][j],dp[i-1][j-v[i]*k]+w[i]*k);
			}
		}
	}
	cout<<dp[n][m]<<endl;
}
二进制优化
int v[N], w[N], dp[N];
void solve()
{
	cin>>n>>m;
	int cnt = 0;
	for(int i = 1;i <= n;i++){
		int a, b, s;
		cin>>a>>b>>s;
		int k = 1;
		while(k <= s){
			cnt++;
			v[cnt] = a*k;
			w[cnt] = b*k;
			s -= k;
			k *= 2;
		}
		if(s > 0){
			cnt++;
			v[cnt] = a*s;
			w[cnt] = b*s;
		}
	}
	n = cnt;//更新物品数量,因为我们用二进制优化打包了物品
	for(int i = 1;i <= n;i++){
		for(int j = m;j >= v[i];j--){
			dp[j] = max(dp[j], dp[j-v[i]]+w[i]);
		}
	}
	cout<<dp[m]<<endl;
}
分组背包
int v[N][N], w[N][N], s[N], dp[N];
void solve()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>s[i];
		for(int j = 0;j < s[i];j++){
			cin>>v[i][j]>>w[i][j];
		}
	}
	for(int i = 1;i <= n;i++){
		for(int j = m;j >= 0;j--){
			for(int k = 0;k < s[i];k++){
				if(v[i][k] <= j)dp[j] = max(dp[j],dp[j-v[i][k]]+w[i][k]);
			}
		}
	}
	cout<<dp[m]<<endl;
	
}
背包方案数
int v[N], w[N], dp[N][N], pl[N][N];
void solve()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++)cin>>v[i]>>w[i];
	for(int i = 1;i <= n;i++){
		for(int j = 0;j <= m;j++){
			dp[i][j] = dp[i-1][j];
			if(j >= v[i])dp[i][j] = max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
		}
	}
	pl[0][0] = 1;
	for(int i = 1;i <= n;i++){
		for(int j = 0;j <= m;j++){
			if(dp[i][j]==dp[i-1][j])
				pl[i][j] = (pl[i][j]+pl[i-1][j])%mod;
			if(j>=v[i]&&dp[i][j]==dp[i-1][j-v[i]]+w[i])
				pl[i][j] = (pl[i][j]+pl[i-1][j-v[i]])%mod;
		}
	}
	int ans = 0;
	for(int i = 0;i <= m;i++){
		if(dp[n][i]==dp[n][m])ans=(ans+pl[n][i])%mod;
	}
	cout<<ans<<endl;
}

并查集

int pre[N];
void init(int x){
    for(int i = 1;i <= x;i++){
        pre[i] = i;
	}
}
int find(int x){
    if(x!=pre[x])pre[x] = find(pre[x]);
    return pre[x];
}
void merge(int a, int b){
    a = find(a), b = find(b);
    pre[a] = b;
}

最短路

单源最短路Dijkstra
#include <bits/stdc++.h>
#include <algorithm>
#define ll long long
#define pii pair<int, int>
#define inf 1e9
using namespace std;
const int N = 2e5+10;
const int mod = 1e9 + 7;
int t, n, m, s;
// 建立邻接表
int vis;
struct node{
	int u, v, w, nex;
}idex[N];
int head[N];
bool vim[N/2];
ll dis[N/2];
void add(int a, int b, int w){
	idex[++vis].u = a;
	idex[vis].v = b;
	idex[vis].w = w;
	idex[vis].nex = head[a];
	head[a] = vis;
}
// 迪杰斯特拉
priority_queue<pii,vector<pii>,greater<pii>>q;
void dijkstra(){
	for(int i = 1;i <= n;i++)dis[i] = inf;
	dis[s] = 0;
	pii f = make_pair(0,s);
	q.push(f);
	while(!q.empty()){
		int top = q.top().second;q.pop();
		if(vim[top])continue;
		vim[top] = true;
		for(int i = head[top];i;i = idex[i].nex){
			int ind = idex[i].v;
			if(dis[ind] > dis[top]+idex[i].w){
				dis[ind] = dis[top]+idex[i].w;
				q.push(make_pair(dis[ind],ind));
			}
		}
	}
}
void solve(){
	cin>>n>>m>>s;
	for(int i = 0;i < m;i++){
		int a, b, c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	dijkstra();
	for(int i = 1;i <= n;i++)cout<<dis[i]<<" ";
}
int main()
{
	// cin>>t;
	// while(t--)
		solve();
	return 0;
}
弗洛伊德最短路
void func(){
    int dis[N][N];
    memset(dis,inf,sizeof(dis));
	for(int i = 0;i < n;i++){
        for(int j = 0;j < n;j++){
            cin>>dis[i][j];
		}
	}
    for(int k = 0;k < n;k++)
       	for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
    //弗洛伊德就是暴力枚举最小值
}
SPFA
vector<node> G[maxn];
bool inqueue[maxn];
int dist[maxn];

void Init()  
{  
    for(int i = 0 ; i < maxn ; ++i){  
        G[i].clear();  
        dist[i] = INF;  
    }  
}  
int SPFA(int s,int e)  
{  
    int v1,v2,weight;  
    queue<int> Q;  
    memset(inqueue,false,sizeof(inqueue)); // 标记是否在队列中 
    memset(cnt,0,sizeof(cnt)); // 加入队列的次数 
    dist[s] = 0;  
    Q.push(s); // 起点加入队列 
    inqueue[s] = true; // 标记 
    while(!Q.empty()){  
        v1 = Q.front();  
        Q.pop();  
        inqueue[v1] = false; // 取消标记 
        for(int i = 0 ; i < G[v1].size() ; ++i){ // 搜索v1的链表 
            v2 = G[v1][i].vex;  
            weight = G[v1][i].weight;  
            if(dist[v2] > dist[v1] + weight){ // 松弛操做 
                dist[v2] = dist[v1] + weight;  
                if(inqueue[v2] == false){  // 再次加入队列 
                    inqueue[v2] = true;  
                    //cnt[v2]++; // 判负环 
                    //if(cnt[v2] > n) return -1; 
                    Q.push(v2);  
                } } }  
    }  
    return dist[e];  
}

二分图

染色法
int bipartite(int s) {  
    int u, v;  
    queue<int>Q;  
    color[s] = 1;  
    Q.push(s);  
    while (!Q.empty()) {  
        u = Q.front();  
        Q.pop();  
        for (int i = 0; i < G[u].size(); i++) {  
            v = G[u][i];  
            if (color[v] == 0) {  
                color[v] = -color[u];  
                Q.push(v);  
            }  
            else if (color[v] == color[u])  
                return 0;  
        }  
    }  
    return 1;  
}
匈牙利算法
vector<int>G[maxn];  
bool inpath[maxn];  // 标记 
int match[maxn];    // 记录匹配对象 
void init()  
{  
    memset(match, -1, sizeof(match));  
    for (int i = 0; i < maxn; ++i) {  
        G[i].clear();  
    }  
}  
bool findpath(int k) {  
    for (int i = 0; i < G[k].size(); ++i) {  
        int v = G[k][i];  
        if (!inpath[v]) {  
            inpath[v] = true;  
            if (match[v] == -1 || findpath(match[v])) { // 递归 
                match[v] = k; // 即匹配对象是“k妹子”的 
                return true;  
            }  
        }  
    }  
    return false;  
}  

void hungary() {  
    int cnt = 0;  
    for (int i = 1; i <= m; i++) {  // m为须要匹配的“妹子”数 
        memset(inpath, false, sizeof(inpath)); // 每次都要初始化 
        if (findpath(i)) cnt++;  
    }  
    cout << cnt << endl;  
}
int v1, v2;  
bool Map[501][501];  
bool visit[501];  
int link[501];  
int result;  

bool dfs(int x)  {  
    for (int y = 1; y <= v2; ++y)  {  
        if (Map[x][y] && !visit[y])  {  
            visit[y] = true;  
            if (link[y] == 0 || dfs(link[y]))  {  
                link[y] = x;  
                return true;  
            } } }  
    return false;  
}  


void Search()  {  
    for (int x = 1; x <= v1; x++)  {  
        memset(visit,false,sizeof(visit));  
        if (dfs(x))  
            result++;  
    }
}

最小生成树

Kruskal
#include<bits/stdc++.h>
#include<algorithm>
#include<functional>
#define inf 1e9
#define ll long long
#define pii pair<int,int>
using namespace std;
const int N = 2e5+10;
const int mod = inf+7;
int t, n, m, k;
int ans;
struct edge{
	int u, v, w;
	edge(int x, int y, int z):u(x), v(y), w(z){};
};
vector<edge> L;
vector<edge> res;
int pre[N];
bool vis[N];
bool cmp(edge x, edge y){
	return x.w < y.w;
}
int find(int x){
	if(x!=pre[x])pre[x] = find(pre[x]);
	return pre[x];
}
void kruskal(){
	for(int i = 1;i <= n;i++){
		pre[i] = i;
	}
	for(int i = 0;i < m;i++){
		int a = find(L[i].u);
		int b = find(L[i].v);
		if(a != b){
			res.push_back(L[i]);
			ans += L[i].w;
			pre[a] = b;
		}
	}
}
void solve(){
	cin>>n>>m;
	for(int i = 0;i < m;i++){
		int a, b, c;
		cin>>a>>b>>c;
		L.push_back(edge(a,b,c));
	}
	sort(L.begin(),L.end(),cmp);
	kruskal();
	if(res.size() < n-1)cout<<"orz\n";
	else cout<<ans<<"\n";
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	// cin>>t;
	t = 1;
	while(t--)
    	solve();
    return 0;
}
Prim
struct node {  
    int v, len;  
    node(int v = 0, int len = 0) :v(v), len(len) {}  
    bool operator < (const node &a)const {  // 加入队列的元素自动按距离从小到大排序 
        return len> a.len;  
    }  
};
vector<node> G[maxn];
int vis[maxn];
int dis[maxn];
void init() {  
    for (int i = 0; i<maxn; i++) {  
        G[i].clear();  
        dis[i] = INF;  
        vis[i] = false;  
    }  
}  
int Prim(int s) {  
    priority_queue<node>Q; // 定义优先队列 
    int ans = 0;  
    Q.push(node(s,0));  // 起点加入队列 
    while (!Q.empty()) {   
        node now = Q.top(); Q.pop();  // 取出距离最小的点 
        int v = now.v;  
        if (vis[v]) continue;  // 同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的须要直接跳过。 
        vis[v] = true;  // 标记一下 
        ans += now.len;  
        for (int i = 0; i<G[v].size(); i++) {  // 开始更新 
            int v2 = G[v][i].v;  
            int len = G[v][i].len;  
            if (!vis[v2] && dis[v2] > len) {   
                dis[v2] = len;  
                Q.push(node(v2, dis[v2]));  // 更新的点加入队列并排序 
            }  
        }  
    }  
    return ans; 
}

欧拉函数

欧拉函数是小于 x x x 的整数中与 x x x 互质的数的个数,用 H ( x ) H(x) H(x) 表示, H ( 1 ) = 1 H(1) = 1 H(1)=1

计算通式: H ( x ) = x × ∏ i = 1 n ( 1 − 1 p i ) H(x) = x\times \prod_{i=1}^n(1-\frac{1}{p_i}) H(x)=x×i=1n(1pi1) (其中 p i p_i pi x x x 的所有质因数)
在这里插入图片描述

在这里插入图片描述

埃筛求欧拉函数

在这里插入图片描述

const int N = 1e5+10;
int phi[N];
void euler(int n){
    for(int i = 1;i <= n;i++)phi[i] = i;
    for(int i = 2;i <= n;i++){
        if(i == phi[i]){
            for(int j = i;j <= n;j += i){
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }
}
欧筛求欧拉函数

在这里插入图片描述

const int N = 1e5+10;
int phi[N];
int prime[N];
bool vis[N];
void euler(int n){
    phi[1] = 1;
    for(int i = 2;i <= n;i++){
        if(!vis[i]){
            prime[++prime[0]] = i;
            phi[i] = i-1;
        }
        for(int j = 1;j <= prime[0]&&prime[j]*i<=n;j++){
            vis[i*prime[j]] = 1;
            if(!i%prime[j]){
                phi[i*prime[j]] = phi[i]*prime[j];
                break;
            }
            else{
                phi[i*prime[j]] = phi[i]*phi[prime[j]];
            }
        }
    }
}

线段树

#include<bits/stdc++.h>
#include<algorithm>
#define inf 1e9
#define ll long long
#define pii pair<int,int>
using namespace std;
const int N = 5e5+10;
int n, m, t, s;
int a[N];
int ans;
struct segment_tree
{
    //节点,存储左右儿子和该节点的值
    struct node{
        int l, r,sum;
        int lz;//懒标记
    }tr[N*4];
    // 建立线段树
    void build(int p, int l, int r){
        tr[p].l = l, tr[p].r = r;
        if(l == r){
            tr[p].sum = a[l];
            return ;
        }
        int mid = (l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        // 该节点的权值为左右儿子的权值之和
        tr[p].sum = tr[p<<1].sum + tr[p<<1|1].sum;
    }
// 类型一
    // 区间查询
    int search(int p, int l, int r){
        if(tr[p].l >= l&&tr[p].r <= r){
            return tr[p].sum;
        }
        if(tr[p].r < l||tr[p].l > r)return 0;
        int s = 0;
        if(tr[p<<1].r >= l) s += search(p<<1,l,r);
        if(tr[p<<1|1].l <= r) s += search(p<<1|1,l,r); 
        return s;
    }
    // 单点修改
    void add(int p, int dis, int k){
        if(tr[p].l==tr[p].r){
            tr[p].sum += k;
            return ;
        }
        if(dis <= tr[p<<1].r)add(p<<1,dis,k);
        else add(p<<1|1,dis,k);
        tr[p].sum = tr[p<<1].sum+tr[p<<1|1].sum;//更新对应父节点的值
        return ;
    }
// 类型二
    // 区间修改
    void modify(int p, int l, int r, int k){
        if(tr[p].l >= l&&tr[p].r <= r){
            tr[p].sum += k;
            tr[p].lz += k;
            return ;
        }
        int mid = l+r>>1;
        if(l <= mid) modify(p<<1,l,r,k);
        if(r > mid) modify(p<<1|1,l,r,k);
    }
    // 单点查询
    void query(int p, int x){
        ans += tr[p].sum;
        if(tr[p].l==tr[p].r)return ;
        int mid = tr[p].l+tr[p].r>>1;
        if(x <= mid)query(p<<1,x);
        else query(p<<1|1,x);
    }
// 类型三
    void push_down(int p){
        if(tr[p].lz!=0){
            tr[p<<1].lz += tr[p].lz;
            tr[p<<1|1].lz += tr[p].lz;
            int mid = tr[p].l+tr[p].r>>1;
            tr[p<<1].sum += tr[p].lz*(mid - tr[p<<1].l+1);
            tr[p<<1|1].sum += tr[p].lz*(tr[p<<1|1].l-mid);
            tr[p].lz = 0;
        }
    }
    //区间修改 
    void modifycpy(int p, int l, int r, int k){
        if(tr[p].r <= r&&tr[p].l >= l){
            tr[p].sum += k*(tr[p].r-tr[p].l+1);
            tr[p].lz += k;
            return ;
        }
        push_down(p);
        if(tr[p<<1].r >= l)modifycpy(p<<1,l,r,k);
        if(tr[p<<1|1].l <= r)modifycpy(p<<1|1,l,r,k);
        tr[p].sum = tr[p<<1].sum + tr[p<<1|1].sum;
    }   
    //区间查询
    int searchcpy(int p, int l,int r){
        if(tr[p].l >= l&&tr[p].r <= r){
            return tr[p].sum;
        }
        if(tr[p].r < l||tr[p].l > r)return 0;
        push_down(p);
        int res = 0;
        if(tr[p<<1].r >= l)res += searchcpy(p<<1,l,r);
        if(tr[p<<1|1].l <= r)res += searchcpy(p<<1|1,l,r);
        return res;
    }
}ST;
void solve(){
    cin>>n;
    for(int i = 1;i <= n;i++)
        cin>>a[i];
    ST.build(1,1,n);
    for(int i = 1;i <= 4;i++){
        int x, y;
        cin>>x>>y;
        int ans = ST.search(1,x,y);
        cout<<ans<<"\n";
    }
}
int main(){
    solve();
    return 0;
}

计算几何

向量基本用法
struct node {  
    double x; // 横坐标 
    double y; // 纵坐标 
};  

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;  // 返回一个点 
}
求多边形面积
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);  
    }  
    system("pause");  
    return 0;  
}
判断线段相交
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; 
}
求解三角形外心
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; 
}
极角排序
double cross(point p1, point p2, point q1, point q2) {  // 叉积计算 
    return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);  
}  
bool cmp(point a, point b)  {  
    point o;  
    o.x = o.y = 0;  
    return cross(o, b, o, a) < 0; // 叉积判断 
}  
sort(convex + 1, convex + cnt, cmp); // 按角排序, 从小到大 

字符串

博弈论

巴什博弈

巴什博奕:只有一堆 n n n 个物品,两个人轮流从中取物,规定每次最少取一个,最多取 m m m 个,最后取光者为胜。

if(n%(m+1)==0)  cout<<"后手必胜"<<endl;  
else cout<<"先手必胜"<<endl; 

解释:一轮最多拿的就是 1 + m 1+m 1+m 个,所以控制下去,最后的不到( 1 + m 1+m 1+m)的物品肯定会被后手拿到的。

威佐夫博弈

有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。

解题核心就是:看两个数的差值 t t t 是不是满足 $\frac{(sqrt(5)+1)}{2}\times t=min(n1,n2) $ ;

#include <cstdio>  
#include <cmath>  
#include <iostream>  
using namespace std;  
int main()  
{  
    int n1,n2,temp;  
    while(cin>>n1>>n2)  
    {  
        if(n1>n2)  swap(n1,n2);  
        temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);  
        if(temp==n1) cout<<"后手必胜"<<endl;  
        else cout<<"先手必胜"<<endl;  
    }  
    return 0;  
}  
尼姆博弈

有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。

解题核心:把每堆物品数全部异或起来,如果得到的值为 0 0 0 ,那么先手必败,否则先手必胜。

#include <cstdio>  
#include <cmath>  
#include <iostream>  
using namespace std;  
int main()  
{  
    int n,ans,temp;  
    while(cin>>n)  
    {  
        temp=0;  
        for(int i=0;i<n;i++)  
        {  
            cin>>ans;  
            temp^=ans;  
        }  
        if(temp==0)  cout<<"后手必胜"<<endl;  
        else cout<<"先手必胜"<<endl;  
    }  
    return 0;  
}  
斐波拉契博弈

有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。

解题核心:先手胜当且仅当n不是斐波那契数( n n n 为物品总数)

#include <iostream>    
#include <string.h>    
#include <stdio.h>    
using namespace std;    
const int N = 55;      
int f[N];     
void Init()    
{    
    f[0] = f[1] = 1;    
    for(int i=2;i<N;i++)    
        f[i] = f[i-1] + f[i-2];    
}      
int main()    
{    
    Init();    
    int n;    
    while(cin>>n)    
    {    
        if(n == 0) break;    
        bool flag = 0;    
        for(int i=0;i<N;i++)    
        {    
            if(f[i] == n)    
            {    
                flag = 1;    
                break;    
            }    
        }    
        if(flag) puts("Second win");    
        else     puts("First win");    
    }    
    return 0;    
}   
环形博弈

n个石子围成一个环,每次取一个或者取相邻的2个。

解题核心:石子数目小于等于2 先手胜,其他 后手胜。

对称博弈

n n n个石子围成环,每次只能取相邻的 1 1 1 ~ k k k 个 。

( 1 ) (1) (1) 如果 k < n k<n k<n

如果 k = 1 k = 1 k=1,如果 n % 2 = 0 n\%2=0 n%2=0 ,则后手赢。

如果 k > 1 k > 1 k>1,后手赢。(先手取什么位置后手就取对称的位置,这样保证后手永远能取到 )

( 2 ) (2) (2) 如果 n ≤ k n\leq k nk

先手赢

  • 3
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值