zoj 3165 Party of 8g (最大点权独立集)

本文探讨了如何解决二分图中的最大点权独立集问题,并将其转化为求最小点权覆盖集的问题,进一步利用Dinic算法求解最大流来找到最优解。文章详细介绍了算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Party of 8g

Time Limit: 5 Seconds      Memory Limit: 56797 KB      Special Judge

As all you know, DD is a hospitable person. On Saint Valentine's Day, DD is going to arrang a party for girls and boys. However, as you may don't know, DD hate the so-called "8g" relationship. So, he will not invite a boy and a girl who have 8g at the same time.

DD's friends are M boys (labeled 1..M) and N girls (labeled 1..N), and each of them has a "lovely value". Now, DD want to invite some of them, satisfying that no 8g exists among invited people, and the total lovely value of all the invited people can be maximal.

Input

Multiple test cases, each cases consists of three parts.

First part, one line, three integers MN and S.

Second part, two lines. First line, M integers, boys' lovely values from the 1st to the Mth. Second line, N integers, girls' lovely values from the 1st to the Nth.

Third part, S lines. Each line consists of two integers X and Y, means that the boy X and the girl Y have 8g.

One blank line between test cases.

Output

For each test case, your output should include three parts.

First part, one line, three integers XA and BX is the maximal total lovly value. A and B are the numbers of boys and girls invited.

Second part, one line, A integers, labels of the invited boys.

Third part, one line, B integers, labels of the invited girls.

If multiple solutions exist, output any of them.

Data Restriction

0 <= MN <= 100; 0 <= S <= M*N.

1 <= lovely value <= 1024.

Sample Input

5 5 10
1 3 5 7 9
2 4 6 8 10
1 4
5 3
2 4
3 5
1 1
2 4
1 2
3 4
1 5
5 5

Sample Output

37 1 5
4
1 2 3 4 5

Author: CUI, Tianyi
Source: ZOJ Monthly, February 2009


求二分图的最大点权独立集, 等于总权值 - 最小点权覆盖集。最小点权覆盖集就是最小割。最小割的方案是在求过最大流的残留网络中,从s出发遍历所有的点,构成集合S。再根据S判断。

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<cmath>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 1e9;
const double eps = 1e-6;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> P;
#define fi first
#define se second

struct Edge {
  int from, to, cap, flow;
};

struct Dinic {
  int n, m, s, t;
  vector<Edge> edges;    // 边数的两倍
  vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
  bool vis[maxn];        // BFS使用
  int d[maxn];           // 从起点到i的距离
  int cur[maxn];         // 当前弧指针

  void ClearAll(int n) {
    for(int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }

  void ClearFlow() {
    for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
  }

  void AddEdge(int from, int to, int cap) {
    //cout << from << ' ' << to << ' ' << cap << endl;
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
  }

  bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    vis[s] = 1;
    d[s] = 0;
    while(!Q.empty()) {
      int x = Q.front(); Q.pop();
      for(int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if(!vis[e.to] && e.cap > e.flow) {
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
  }

  int DFS(int x, int a) {
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int& i = cur[x]; i < G[x].size(); i++) {
      Edge& e = edges[G[x][i]];
      if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i]^1].flow -= f;
        flow += f;
        a -= f;
        if(a == 0) break;
      }
    }
    return flow;
  }

  int Maxflow(int s, int t) {
    this->s = s; this->t = t;
    int flow = 0;
    while(BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }

  vector<int> boy, girl;
  void get_ans(int a, int b){
    boy.clear();girl.clear();
    int vis[maxn];
    memset(vis, 0, sizeof vis);
    queue<int> q;
    q.push(0);
    while(!q.empty()){
        int pos = q.front();q.pop();
        for(int i = 0;i < G[pos].size();i++){
            Edge& e = edges[G[pos][i]];
            if(e.cap > e.flow && !vis[e.to]){
                vis[e.to] = 1;
                q.push(e.to);
            }
        }
    }
    for(int i = 1;i <= a;i++){
        if(vis[i]==1)
            boy.push_back(i);
    }
    for(int i = a+1;i <= a+b;i++){
        if(vis[i]==0)
            girl.push_back(i-a);
    }
  }
};

Dinic g;

int main(){
    int a, b, m;
    while(scanf("%d%d%d", &a, &b, &m) != EOF){
        g.ClearAll(a+b+5);
        int source = 0, sink = a+b+1;
        int total = 0;
        for(int i = 1;i <= a;i++){
            int x;
            scanf("%d", &x);
            total += x;
            g.AddEdge(source, i, x);
        }
        for(int i = 1;i <= b;i++){
            int x;
            scanf("%d", &x);
            total += x;
            g.AddEdge(i+a, sink, x);
        }

        while(m--){
            int x, y;
            scanf("%d%d", &x, &y);
            g.AddEdge(x, a+y, INF);
        }
        cout << total-g.Maxflow(source, sink);
        g.get_ans(a, b);
        cout << ' ' << g.boy.size() << ' ' << g.girl.size() << endl;
        int bsize = g.boy.size();
        for(int i = 0;i < bsize-1;i++){
            cout << g.boy[i] << ' ';
        }
        if(bsize>=1)
            cout << g.boy[bsize-1];
        cout << endl;
        int gsize = g.girl.size();
        for(int i = 0;i < gsize-1;i++){
            cout << g.girl[i] << ' ';
        }
        if(gsize>=1)
            cout << g.girl[gsize-1];
        cout << endl;

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值