T151892


前言

寒假集训考试题。当时甚至想到最小生成树上了。wtcl


题目大意

同学们要去参观。

同学们不能单独参观,必须结伴同行。为了公平,任意两名同学都要结伴去参观一次,即大家一共会进行 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2次参观。

另外,由于同学们之间的亲密值不同,每个人都在心目中有一个与其他同学关系的排序,每个人都想按照这个顺序依次与每个人结伴参观。

请你帮忙计算,能否安排一个合适的参观顺序?以及最少需要多少天才能让完成同学们的参观计划?如果无法安排一个满足条件的参观计划,输出-1

3 ≤ n ≤ 1000 3 \leq n \leq 1000 3n1000


思路

首先,图论肯定看出来了。之后考虑建模,也是本题最难的地方。首先不能把一个人当成一个点,否则出来的感觉会很别扭。由于每一组人早晚都得参加,所以可以把每一组看成一个点。之后是拓扑排序,按照顺序进行拓扑即可。

每一组看成一个点有一个小技巧。就是用一个公式代表两个点。可以是 ( u − 1 ) ∗ n + v (u-1)*n+v (u1)n+v,这样 1 , 1 1,1 1,1 就是 1 1 1 1 , 2 1,2 1,2 就是 2 2 2,就不会重复了。这个可以根据题目去设计。


代码

#include<iostream>
#include<algorithm>
#include <cstring>
#include <queue>

using namespace std;
typedef long long ll;
const ll MAXN = 1e6;
const ll MAXM = 1e6;
struct edge {
    ll to, nxt;
} e[MAXM];
ll head[MAXN], tot;

void add(ll u, ll v) {
    e[++tot].nxt = head[u];
    e[tot].to = v;
    head[u] = tot;
}

ll n, ind[MAXN], dp[MAXN], ans;

ll node_id(ll u1, ll u2) {
    if (u1 > u2) {
        swap(u1, u2);
    }
    return (u1 - 1) * n + u2;
}

int main() {
    scanf("%lld", &n);
    for (int i = 1; i <= n; ++i) {
        ll a;
        scanf("%lld", &a);
        ll lid = node_id(i, a);
        for (int j = 1; j < n - 1; ++j) {
            scanf("%lld", &a);
            ll id = node_id(i, a);
            add(lid, id);
            ind[id]++;
            lid = id;
        }
    }
    ll num = node_id(n - 1, n);
    queue<ll> q;
    for (int i = 1; i <= num; ++i) {
        if (ind[i] == 0) {
            q.push(i);
            dp[i] = 1;
            ans = 1;
        }
    }
    ll cnt = 0;
    while (!q.empty()) {
        ll u = q.front();
        q.pop();
        cnt++;
        for (ll i = head[u]; i; i = e[i].nxt) {
            ll v = e[i].to;
            ind[v]--;
            dp[v] = max(dp[v], dp[u] + 1);
            ans = max(ans, dp[v]);
            if (ind[v] == 0) {
                q.push(v);
            }
        }
    }
    if (cnt != num) {
        printf("-1\n");
    } else {
        printf("%lld\n", ans);
    }
    return 0;
}

总结

本题的难点在于想到怎么去建模。其实图的结点不一定是每一个单独的点,其实结点是“状态”。有的时候状态只有一个,而有的时候多个数才能组成一个状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值