20241016下午

P1040 启发式图染色问题(color)

我们可以先想一棵树的情况,如下图所示

image

但是显然这个节点数量是 \(2 ^ k\),我们可以考虑二分图,然后你推着推着就会发现一个建图方案

image

具体来说,我们可以现在左边创建一个颜色为 \(1\) 的结点,然后我们想让颜色数量尽量多,我们直接在右边创建一个颜色为 \(2\) 的结点,并让 \(1\) 连向 \(2\) ,我们又可以在左边创建一个颜色为 \(3\) 的结点, 但是以当前点的颜色数量而言的话,还不足以创建一个颜色为 \(3\) 的点,所以我们可以在右边创建一个颜色为 \(1\) 的点,那么就可以维持了,然后让 \(2, 1\) 向 \(3\) 连边,我们考虑在左边创建一个颜色为 \(4\) 的点,但是还需要在右边创建一个颜色为三的点,而在右边创建一个颜色为 \(3\) 的点又需要在左边创建一个颜色为 \(2\) 的点,以此类推,但是如果我们在右边创建一个颜色为 \(4\) 的点,就只需要在左边创建一个颜色为 \(2\) 的点,所以我们可以果断在右边创建一个颜色为 \(4\) 的点,在左边创建一个颜色为 \(2\) 的点,那么按照这个规律向下推,我们便可以构造出一个颜色为 \(2 \times (k + 2)\) 的图

#include <bits/stdc++.h>

using namespace std;

using Pii = pair<int, int>;

#define int long long

int k, n;

vector<Pii> e;

signed main() {
  freopen("color.in", "r", stdin);
  freopen("color.out", "w", stdout);
  cin >> k;
  n = (2 + k) * 2;
  for (int i = 3; i <= n; i++) {
    for (int j = 1; j < i / 2 * 2; j++) {
      if ((j & 1) ^ (i & 1)) {
        e.push_back({i, j});
      }
    }
  }
  cout << n << " " << e.size() << " 2\n";
  for (int i = 1; i <= n; i++) {
    if (i == n) {
      cout << !(i % 2) + 1;
    }
    else cout << !(i % 2) + 1 << " ";
  }
  cout << "\n";
  for (auto [x, y] : e) {
    cout << x << " " << y << "\n";
  }
  return 0;
}

是的,代码就这么短

自由组队(teamup)

我们可以考虑直接暴搜每个队伍的长度,但是我们要保证长度是非严格递增的,我测试了一下, \(n = 60\) 大概只有 \(1e6\) 种,我们就可以放心大胆的暴搜,每次我们对于每个队伍选人,由于长度是严格递增的我们肯定是先选满足可以加入这个队伍中的 \(r_i\) 小的,所以暴搜加贪心即可

#include<bits/stdc++.h>

using namespace std;

using Pii = pair<long long, int>;

const int N = 100 + 5;

const long long INF = 1e18;

struct node {
  int l, r;
}a[N];

int t, n;

long long w[N], ans;

vector<int> v[N];

map<Pii, long long> dp;

void dfs(long long now, int cnt, int last, long long val) {
  if (dp.count({now, last}) && dp[{now, last}] > val) {
    return ;
  }
  dp[{now, last}] = val;
  if (!now) {
    ans = max(ans, val);
  }
  for (int i = last; i <= n - cnt + 1; i++) {
    long long tmp = now;
    int tot = 0;
    for (auto cur : v[i]) {
      if (tmp & (1ll << (cur - 1))) {
        tmp ^= (1ll << (cur - 1));
        tot++;
      }
      if (tot == i) {
        break;
      }
    }
    if (tot == i) {
      dfs(tmp, cnt + i, i, val + w[i]);
    }
  }
}

bool cmp(node _x, node _y) {
  return _x.l < _y.l;
}

void Solve() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].l >> a[i].r;
  }
  for (int i = 1; i <= n; i++) {
    cin >> w[i];
  }
  sort(a + 1, a + n + 1, cmp);
  for (int i = 1; i <= n; i++) {
    vector<Pii> tmp;
    for (int j = 1; j <= n; j++) {
      if (a[j].l <= i && a[j].r >= i) {
        tmp.push_back({a[j].r, j});
      }
    }
    sort(tmp.begin(), tmp.end());
    for (auto cur : tmp) {
      v[i].push_back(cur.second);
    }
  }
  ans = -INF;
  dfs((1ll << n) - 1, 1, 1, 0);
  if (ans <= -1e17) {
    cout << "impossible\n";
  }
  else cout << ans << "\n";
  for (int i = 1; i <= n; i++) {
    v[i].clear();
  }
  dp.clear();
}

int main(){
  ios::sync_with_stdio(0);
  cin.tie(0);
  freopen("teamup.in", "r", stdin);
  freopen("teamup.out", "w", stdout);
  cin >> t;
  while (t--) {
    Solve();
  }
  return 0;
}
/*
1
3
2 3
1 2
2 2
4 5 100
*/
posted @ 2024-10-17 19:58  libohan0518  阅读(27)  评论(0)    收藏  举报