acm模板1


扩展域并查集

/**
 * 扩展域并查集
 * 例题链接:https://www.luogu.com.cn/problem/P2024
 **/
 #include <iostream>
 #include <algorithm>
 #include <cstring>

using namespace std;

#define endl "\n"
const int N = 1e6 + 5;

//吃 a + n // 被 a + 2n 吃
int f[N], n, k, ans;

//给每一个子节点指定初始的父节点为自己
void init() { for (int i = 1; i <= 3 * n; i++) f[i] = i; }
 
//寻找根节点 加路径压缩
int find(int x) { return x == f[x]?x:f[x] = find(f[x]); }

int main()
{
    scanf("%d%d", &n, &k); //cin >> n >> k;
    init();
    while (k -- ) {
        int c, a, b;
        scanf("%d%d%d", &c, &a, &b); //cin >> c >> a >> b;
        if (a > n || b > n) { ans ++; continue; }
        //a是否等于b
        if (c == 1) {
            int u = find(a), v = find(b);
            //如果 a的猎物不是 b 且 a的天敌不是b
            if (find(a + n) != find(b) && find(a + 2 * n) != find(b)) {
                if (u != v) {
                    f[u] = v;
                    //合并猎物
                    if (find(a + n) != find(b + n)) 
                        f[find(a + n)] = find(b + n);
                    //合并天敌
                    if (find(a + 2 * n) != find(b + 2 * n)) 
                        f[find(a + 2 * n)] = find(b + 2 * n);
                }
            }
            else ans++;
        }
        //a是否吃b
        if (c == 2) {
            if (a == b) { ans++; continue; }
            //a b 不是同类且 b的食物不是 a 
            if (find(a) != find(b) && find(a) != find(b + n)) {
                //a的猎物和 b 是一类, a 和 b的捕食者是一类 a的捕食者是 b的猎物
                if (find(a + n) != find(b))
                    f[find(a + n)] = find(b);
                if (find(a) != find(b + 2 * n)) 
                    f[find(a)] = find(b + 2 * n);
                if (find(a + 2 * n) != find(b + n)) 
                    f[find(a + 2 * n)] = find(b + n);
            }
            else ans++;
        }
    }
    printf("%d\n", ans); //cout << ans << endl;
    return 0;
}

//============================================

*带权并查集例题

 * 链接:https://www.luogu.com.cn/problem/P1196
 **/
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 3e4 + 5;

//dist[i] 节点i到上级的距离 length[i] 以i为根节点的高度
int fa[N], dist[N], length[N];
int x, y, n;
char t;

int find(int x) {
    if (x == fa[x]) return x;
    //求出根节点的同时更新fa[x] 到 根节点的距离
    int fx = find(fa[x]);
    //求出x的根节点的同时让x指向根节点 并更新dist[x] 为x到根节点的距离
    dist[x] += dist[fa[x]];
    //将父节点更新为根节点
    return fa[x] = fx;
}

void merege(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx == fy) return ;
    //将一堆的根节点作为另一堆根节点的上级
    fa[fx] = fy;
    //更新作为子结点的根节点到其父节点的距离 同时更新合并后两堆的总数
    dist[fx] += length[fy], length[fy] += length[fx];
}

int query(int x, int y) {
    //由于不知道x和y是否直接指向根节点, 所以需要求一遍x 和 y到根节点的距离
    int fx = find(x), fy = find(y);
    if (fx != fy) return -1;
    return abs(dist[x] - dist[y]) - 1;
}


int main() {
    scanf("%d", &n);
    for (int i = 1; i <= N; i ++ ) fa[i] = i, length[i] = 1;
    while (n -- ) {
        //cin >> t;
        getchar();getchar();
        scanf("%c", &t); // 如果用cin >> t; 就不需要getcahr() scanf()
        scanf("%d%d", &x, &y);
        if (t == 'M') merege(x, y);
        else printf("%d\n", query(x, y));
    }
    return 0;
}

poj1163

//================
暴力递归
if (i == n) {
    MaxSum[i][j] = d[i][j];
} else {
    int x = dpMaxSum(i + 1, j, n);
    int y = dpMaxSum(i + 1, j + 1, n);
    MaxSum[i][j] = max(x, y) + d[i][j];
}

//===============
记忆化搜索
#include <iostream>
#include <string.h>
#define MAXN 105

using namespace std;

int MaxSum[MAXN][MAXN],d[MAXN][MAXN];

int dpMaxSum(int i, int j, int n){
    if(MaxSum[i][j] != -1) {
    //为了防止重复计算带来的时间超限,对于已经求得最大和的该点,直接使用结果,不再进行重复计算。
        return MaxSum[i][j];
    }
    if(i == n){
        MaxSum[i][j] = d[i][j];
    }
    else{
        int x = dpMaxSum(i + 1, j,n);
        int y = dpMaxSum(i + 1, j + 1,n);
        MaxSum[i][j] = max(x,y) + d[i][j];
    }
    return MaxSum[i][j];
}

//===============
二维迭代
#include <iostream>
#include <string.h>
#define MAXN 105

using namespace std;

int MaxSum[MAXN][MAXN],d[MAXN][MAXN];

int dpMaxSum(int i, int j, int n){
    for(int i = 1; i <= n; i++){
        MaxSum[n][i] = d[n][i];
    }
    for(int i = n - 1; i>=1; i--){
        for(int j = 1; j <= i; j++){
            MaxSum[i][j] = max(MaxSum[i + 1][j],MaxSum[i + 1][j + 1]) + d[i][j];
        }
    }
    return MaxSum[1][1];
}

//=================
一维迭代优化
#include <iostream>
#include <string.h>
#define MAXN 105

using namespace std;

int MaxSum[MAXN],d[MAXN][MAXN];

int dpMaxSum(int i, int j, int n){
    for(int i = 1; i <= n; i++){
        MaxSum[i] = d[n][i];
    }
    for(int i = n - 1; i>=1; i--){
        for(int j = 1; j <= i; j++){
            MaxSum[j] = max(MaxSum[j],MaxSum[j + 1]) + d[i][j];
        }
    }
    return MaxSum[1];
}

最大子段和

ll Maxsum(int n){
    ll dp = arr[0];
    ll ans = 0;
    ans = max(ans, dp);
    for(int i = 1; i < n; i++){
        if(dp >= 0){
            dp += arr[i];
        }
        else{
            dp = arr[i];
        }
        ans = max(dp,ans);
    }
    return ans;
}

矩阵连乘

#include <iostream>

using namespace std;

const int size = 105;

int m[size][size],s[size][size];//m[i][j]的值是i - j的最小乘数,s[i][j]则是记录过程
int p[size];//存储矩阵的第一个行和中间矩阵的列数以及最后一个矩阵的列

void Min_matrix(int n){
    for(int l = 2; l <= n; l++){//矩阵连乘的单元规模
        for(int i = 1; i <= n - l + 1; i++){//对不同规模的矩阵连乘单元,确定共有多少单元
            int j = i + l - 1;
            m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];//先赋一个初值,以进行下面的比较
            s[i][j] = i;//i - j 的最小相乘次数的决策点
            for(int k = i + 1; k < j; k++){//通过遍历中间点来找到最优决策点
                int temp = m[i][k] + m[k + 1][j] + p[i - 1]*p[k]*p[j];
                if(m[i][j] > temp){
                    m[i][j] = temp;
                    s[i][j] = k;
                }
            }
        }
    }
}

滑雪

#include <iostream>
 
using namespace std;
 
const int maxn = 105;
const int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1}; 
const int inf = 0x7fffffff;
 
int g[maxn][maxn], f[maxn][maxn];
int r, c, ans = -inf;
 
inline bool check(int x1, int y1, int x2, int y2)
{
    if (g[x1][y1] >= g[x2][y2]) return false;
    if (x1 <= 0 || x1 > r || y1 <= 0 || y1 > c) return false;
    return true;
}
 
int dfs(int i, int j)
{
    if (f[i][j]) return f[i][j];
    f[i][j] = 1;
    for (int d = 0; d < 4; d++) {
        int x = i + dx[d], y = j + dy[d];
        if (!check(x, y, i, j)) continue;
        f[i][j] = max(dfs(x, y) + 1, f[i][j]);
    }
    return f[i][j];
}
 
int main()
{
    cin >> r >> c;
    for (int i = 1;  i <= r; i++) {
        for (int j = 1; j <= c; j++) {
            cin >> g[i][j];
        }
    }
    for (int i = 1; i <= r; i++) {
        for (int j = 1; j <= c; j++) {
            ans = max(dfs(i, j), ans);
        }
    }
    cout << ans << endl;
    return 0;
}

最长上升子序列

朴素O(n^2)
int dp[MAXN],a[MAXN];

int main(){
    int n;
    while(cin>>n,n){
        int maxx = 0;
        memset(dp,1,sizeof(dp));
        for(int i = 1; i <= n; i++){
            cin>>a[i];
        }
        for(int i = 1; i <= n; i++){
            for(int j = 1; j < i; j++){
                if(a[i] > a[j]){
                    dp[i] = max(dp[j] + 1,dp[i]);
                }
            }
        }
        maxx = dp[1];
        for(int i = 1; i <= n; i++){
            maxx = max(maxx,dp[i]);
        }
        cout<<maxx<<endl;
    }
    return 0;
}
//===================
贪心加二分
int dp[MAXN],a[MAXN];


int Lis(int n){
    int l = 1;
    dp[1] = a[1];
    for(int i = 2; i <= n; i++){
        if(a[i] > dp[l]){
            l++;
            dp[l] = a[i];
        }
        else{
            int pos = lower_bound(dp + 1,dp + l,a[i]) - dp;
            dp[pos] = a[i];
        }
    }
    return l;
}

最长公共子序列

void Lcs(char *s1, char *s2){
    for(int i = 1; i <= strlen(s1); i++){
        for(int j = 1; j <= strlen(s2); j++){
            if(s1[i - 1] == s2[j - 1]){
                dpmaxlenth[i][j] = dpmaxlenth[i - 1][j - 1] + 1;
            }
            else if(dpmaxlenth[i - 1][j] >= dpmaxlenth[i][j - 1]){
                dpmaxlenth[i][j] = dpmaxlenth[i - 1][j];
            }
            else{
                dpmaxlenth[i][j] = dpmaxlenth[i][j - 1];
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值