首页 > 其他分享 >AGC039B 题解

AGC039B 题解

时间:2024-08-03 11:08:12浏览次数:7  
标签:二分 int 题解 短路 cin long AGC039B col

因为一条边只能在 \(V_i,V_i+1\) 之间,如果把 \(V_1,V_3,\cdots\) 看作一部分,\(V_2,V_4,\cdots\) 看作一部分,这就是个二分图。

考虑一个二分图怎么“展开”成最多的集合。

考虑答案上界。上界是点对最短路的最大值加一。

如果集合个数超过上界,那么一定存在一条边跨越多个集合。

猜测对于所有情况,上界都可以被构造。

我们发现这是简单的,因为只要沿着最短路构造就行了,设最大值为 \(dis(x,y)\),那么只要令 \(V_i=\{u|dis(x,u)=i-1\}\) 即可。

证明:因为最短路的性质,不存在边 \((u,v)\) 使得 \(|d_u-d_v|>1\)。然后考虑有没有在同集合内的边:因为如果边在集合内,那么沿着最短路树向上找,一定出现奇环,和二分图的性质矛盾。

所以答案即为上界。

于是判定二分图后 \(O(n^3)\) Floyd 或者 \(O(nm)\) bfs 求最短路即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 205;
vector<int> e[N];
int col[N], g[N][N]; bool vis[N];
int n;
bool ok = 1;

void dfs(int x, int fa)
{
    for(int i : e[x])
    {
        if(i == fa) continue;
        if(vis[i])
        {
            if(col[i] != col[x] ^ 1)
                ok = 0;
            continue;
        }
        else
        {
            vis[i] = 1, col[i] = col[x] ^ 1;
            dfs(i, x);
        }
    }
}

int d[N][N];

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    memset(d, 0x3f, sizeof d);
    for(int i = 1; i <= n; i ++)
    {
        string s; cin >> s;
        for(int j = 0; j < n; j ++)
            if(s[j] == '1')
                e[i].push_back(j + 1), g[i][j + 1] = 1, d[i][j + 1] = 1;
    }
    for(int i = 1; i <= n; i ++) d[i][i] = 0;
    for(int i = 1; i <= n; i ++)
        if(!vis[i]) vis[i] = 1, dfs(i, 0);
    if(!ok) return cout << -1, 0;
    for(int k = 1; k <= n; k ++)
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    int ans = 0;
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        ans = max(ans, d[i][j]);
    cout << ans + 1;

    return 0;
}

当然,判二分图也可以扩展域并查集或者带权并查集。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 205;
vector<int> e[N];
int n;

int fa[N << 1];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void merge(int x, int y) {fa[find(x)] = find(y);}
int d[N][N];

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n * 2; i ++) fa[i] = i;
    memset(d, 0x3f, sizeof d);
    for(int i = 1; i <= n; i ++)
    {
        d[i][i] = 0;
        string s; cin >> s;
        for(int j = 0; j < n; j ++)
            if(s[j] == '1')
            {
                e[i].push_back(j + 1);
                d[i][j + 1] = 1;
                merge(i, j + 1 + n);
                merge(i + n, j + 1);
            }
    }
    for(int i = 1; i <= n; i ++)
        if(find(i) == find(i + n)) return cout << -1, 0;
    for(int k = 1; k <= n; k ++)
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    int ans = 0;
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        ans = max(ans, d[i][j]);
    cout << ans + 1;

    return 0;
}

甚至,不需要判二分图,最后枚举每条边,不满足题目要求说明不是二分图。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 205;
vector<int> e[N];
int n;

int d[N][N], g[N][N];

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    memset(d, 0x3f, sizeof d);
    for(int i = 1; i <= n; i ++)
    {
        d[i][i] = 0;
        string s; cin >> s;
        for(int j = 0; j < n; j ++)
            if(s[j] == '1')
            {
                e[i].push_back(j + 1);
                d[i][j + 1] = 1;
                g[i][j + 1] = 1;
            }
    }
    for(int k = 1; k <= n; k ++)
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
    for(int k = 1; k <= n; k ++)
        if(g[j][k] && d[i][j] == d[i][k])
            return cout << -1, 0;
    int ans = 0;
    for(int i = 1; i <= n; i ++)
    for(int j = 1; j <= n; j ++)
        ans = max(ans, d[i][j]);
    cout << ans + 1;

    return 0;
}

标签:二分,int,题解,短路,cin,long,AGC039B,col
From: https://www.cnblogs.com/adam01/p/18340190

相关文章

  • AGC033C 题解
    这里树的直径\(l\)定义为两个有硬币的点的最长距离。做一次操作后,树的直径一定会变短。我们发现,如果在直径端点做操作,直径减一。在非直径端点操作,直径减二。于是变成了一个威佐夫博弈,但是要注意的是,在直径长度为0,1,2的时候,每次都只能让直径减一。因为直径长度为1,先手必......
  • AGC059B 题解
    对于一种构造,考虑怎么表示。可以把相邻不同颜色建图连边。注意到答案不可能小于\(n-1\),否则图不联通,显然不可能。考虑什么情况下是\(n-1\)。图是一棵树。考虑怎么构造出一棵树。因为一种颜色出现次数大于等于这个点的度数,可以考虑可以确定叶子。把剩余度数最小的往最大的......
  • AGC056A 题解
    首先考虑\(n\equiv0\pmod3\)的情况。非常简单,然后考虑\(n\equiv1\pmod3\)的情况。只要把多出来的第一列第一行填满就行了。还要比原来情况多一个连通块。然后考虑\(n\equiv2\pmod3\)的情况。手玩一下,再往左上角添一点东西就行了。#include<bits/stdc++.h>us......
  • AGC044B 题解
    考虑每次更新就跑一遍bfs。\(O(n^4)\),复杂度不对?但是注意到\(dis\)的最大值也就是\(n\),每次更新\(dis\)至少减一。所以最大值最多被更新\(n\)次,一共更新\(O(n^3)\)次,复杂度是对的。直接暴力。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;......
  • ABC267F 题解
    注意到,对于一棵树\(T\)的任一直径\(a-b\),对于任意一点\(u\),离\(u\)最远的点一定是\(a\)或\(b\)。考虑反证:如图,如果存在点\(c\)使得\(dis(u,c)>\max(dis(u,a),dis(u,b))\)。如图,\(a-b\)为直径,\(d2>d1\)。因为有\(d4>d3+d2\),所以有\(d2+d3+d4>2d2+2d3>d1+d2\),所以......
  • ABC266F 题解
    输入的图是一颗基环树。对于\(x,y\),如果把环上的边去掉,得到的森林里\(x,y\)仍然在同一颗树内,那么显然只有一条路。否则一定要经过环,有两条路。于是dfs或着拓扑排序找环即可。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=2e5+......
  • 2024集训8.2模拟赛题解
    考试历程8:30开始考试8:40快速浏览了T1并想了一下,是一道质数的题目,准备打表,打到一半的时候发现空间复杂度会爆,于是改打质数筛暴力了9:30打完T1开始看T2刚开始没思路,先看了T3,跟着样例打了一点,估计可以拿点分吧9:50打完了T3会看T2发现了一点规律(后来知道是错的)跟着思路写了一......
  • gym105167E Erdős-Ginzburg-Ziv 题解
    题意:给\(p\)和\(p-1\)个边权,要用这些边权构造树,每个点编号\(0\simp-1\),使得每个点\(u\)到\(0\)的距离\(\bmod\p=u\),无解输出-1,保证\(p\)是质数、\(p\le10^6\)、边权\(\in[1..p-1]\).Solution考虑加边的过程,树最开始只有根节点0,然后通过加边不断地引入新的点......
  • 优秀的树 - 题解(数学)
    优秀的树时间限制:C/C++2000MS,其他语言4000MS内存限制:C/C++256MB,其他语言512MB描述给定一棵树,其所有边权重均为\(1\),定义\(f(u)=Σ_vdis(u,v)\),v表示树上的所有结点,\(dis(u,v)\)表示结点\(u\)和\(v\)的简单路径的长度。一棵树被称为“优秀”,当且仅当存在两个......
  • 【题解】走路
    I题意简述从原点出发,一步只能向右走、向上走或向左走。恰好走\(N\)步且不经过已走的点共有多少种走法?多组数据,每行输入一个数\(N\)。对于每一组测试数据,每行输出一个数,答案对\(12345\)取模。对于100%的数据,保证\(1\leqN\leq1000\)。时间限制\(1\text{s}\),空......