ICPC2016大连

这篇博客详细解析了ICPC2016大连竞赛中的几道算法题,包括Wrestling Match(二分图染色问题)、Game of Taking Stones(威佐夫博弈模板)、A Simple Math Problem(数学问题求解)、An interesting game(树状数组操作)、Detachment(求最大乘积划分)等,每道题目都给出了详细的解题思路和代码实现。
摘要由CSDN通过智能技术生成

ICPC2016大连

A.Wrestling Match

题意: 给定n个人,这些人可能是好人也可能是坏人,要求好人和坏人才能连边,问是否能够把每个人标记为好人或者坏人

题解: 本题是二分图染色问题。首先需要判断下孤立点,如果是孤立点同时没有染色,那么输出no。然后先把存在染色的连通块染色法判断下,之后再对不存在染色点的连通块再次染色法判断下。不能直接一次dfs染色,因为子节点虽然现在没有被染色,但是可能子节点的颜色是固定的,因此可能会染色错误。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>

using namespace std;

int const N = 1e4 + 10, M = 2e4 + 10;
typedef long long LL;
typedef pair<int, int> PII;

int n, m, T, k1, k2;
int e[M], ne[M], h[N], color[N], idx, vis[N];

void add(int a, int b) {
   
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int dfs(int u, int c) {
   
    color[u] = c;  // 给u号点打上c的颜色
    for (int i = h[u]; i != -1; i = ne[i]) {
     // 遍历所有与i号点相连的点
        int j = e[i];  // 看j号点
        if (!color[j]) {
     // 如果j号点没有染色
            if (!dfs(j, 3 - c)) return 0;  // 如果j号点染色3-c过程中失败
        }
        if (color[j] == c) return 0;  // 如果j号点也染色c颜色
    }
    return 1;  // 如果u号点的所有邻点都没有染色失败
}

int main() {
   
    while(scanf("%d%d%d%d", &n, &m, &k1, &k2) != EOF) {
   
        memset(h, -1, sizeof h);
        memset(color, 0, sizeof color);
        memset(vis, 0, sizeof vis);
        idx = 0;
        for (int i = 1; i <= m; ++i) {
   
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b), add(b, a);
            vis[a] = vis[b] = 1;
        }
        for (int i = 1; i <= k1; ++i) {
   
            int u;
            scanf("%d", &u);
            color[u] = 1;
        }
        for (int i = 1; i <= k2; ++i) {
   
            int u ;
            scanf("%d", &u);
            color[u] = 2;
        }
        int flg = 1;
        for (int i = 1; i <= n; ++i) 
            if (!vis[i] && !color[i]) {
   
                flg = 0;
                printf("NO\n");
                break;
            }
        if (!flg) continue;
        for (int i = 1; i <= n; ++i) {
   
            if (color[i]) {
   
                if (!dfs(i, color[i])) {
     // 如果i号点染色失败
                    flg = 0;  // flg 打上失败标记
                    printf("NO\n");
                    break;
                }
            }
        }
        if (!flg) continue;
        for (int i = 1; i <= n; ++i) {
     // 从1号点开始枚举
            if (color[i]) continue;
            if (!dfs(i, 1)) {
     // 如果i号点染色失败
                flg = 0;  // flg 打上失败标记
                break;
            }
        }
        if (flg) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

C.Game of Taking Stones

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

题解: 威佐夫博弈模板题,套个java高精度即可。

代码:

import java
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值