QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#14892#3020. Rainbow GraphgmyuML 1ms3524kbC++116.9kb2021-10-25 07:02:292022-05-17 01:12:05

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2022-05-17 01:12:05]
  • 评测
  • 测评结果:ML
  • 用时:1ms
  • 内存:3524kb
  • [2021-10-25 07:02:29]
  • 提交

answer

/*
ID: USACO_template
LANG: C++
PROG: https://open.kattis.com/problems/rainbowgraph
*/
#include <iostream>  //cin , cout
#include <fstream>   //fin, fout
#include <stdio.h>   // scanf , pringf
#include <cstdio>
#include <algorithm> // sort , stuff
#include <stack>     // stacks
#include <queue>     // queues
#include <map>
#include <string>
#include <string.h>
#include <set>

using namespace std;

typedef pair<int, int>          pii;
typedef vector<int>             vi;     /// adjlist without weight
typedef vector<pii>             vii;    /// adjlist with weight
typedef vector<pair<int,pii>>   vpip;   /// edge with weight
typedef long long               ll;

#define mp  make_pair
#define ff  first
#define ss  second
#define pb  push_back
#define sz(x)   (int)(x).size()

const int MOD = 1e9+7;  // 998244353;
const int MX  = 2e5+5;   //
const ll  INF = 1e18;    //

#define MAXV 107
#define MAXE 107

struct EDGE {
    int u, v;
    ll w;
    int id;
    bool in;    // mark whether this edge is included or not
    bool operator<(EDGE other) const { return w < other.w; }
};

bool debug;

/** this is a matroid intersection problem
 * learn at https://usaco.guide/adv/matroid-isect?lang=cpp
 * the example code for this problem is at http://www.cs.ucf.edu/~dmarino/progcontests/mysols/northamerica/nac/2018/g.java
 */

int N, E;
EDGE ge[MAXE];
vii adj[2][MAXV];  // for roy/biv = 0/1, record adj at each node
int roy=0, biv=1;
ll totW;

bool removed[MAXE];           // which edge is removed
vector<EDGE> matGraph;        // matroid graph
ll FACTOR = (ll)500;
int src, des;
ll dist[MAXE];
int p[MAXE];

/// check whether the graph is connected
bool visited[MAXV];
void dfs(int p, int u) {
    if(visited[u]) return;
    visited[u] = true;
    for(auto x : adj[p][u]) {
        if(!ge[x.ss].in) continue;
        int nxt = x.ff;
        if(!visited[nxt]) dfs(p, nxt);
    }
}
bool connected(int p){
    for(int i=1; i<=N; i++) visited[i] = false;
    dfs(p, 1);
    for(int i=1; i<=N; i++)
        if(!visited[i]) return false;
    return true;
}

// getMatGraph
void getMatGraph(){
    // Set up according to remove.
    for (int i=1; i<=E; i++) ge[i].in = !removed[i];
    matGraph.clear();

    // if removing an edge still lead to connected graph, connect this edge to src and des in MatGraph
    // Add in all edges for removing an edge from roy or biv.
    for (int i=1; i<=E; i++) {
        if (!ge[i].in) continue;
        // For roy, going from source. If still connected after removing an edge, connect source to i and make weight negative
        // For biv, to destination.
        ge[i].in = false;
        if (connected(roy)) {
            matGraph.pb({src, i, -FACTOR*ge[i].w + 1LL, -1, true});
            if(debug) cout << " .. matGraph " << i << "th edge can be removed for roy " << -FACTOR*ge[i].w + 1LL << endl;
        }
        if (connected(biv)) {
            matGraph.pb({i, des, 0LL + 1LL, -1, true});
            if(debug) cout << " .. matGraph " << i << "th edge can be removed for biv 1" << endl;
        }
        ge[i].in = true;
    }

    // Sort out items in and out of our set.
    vi rSet, bSet;
    rSet.clear(); bSet.clear();
    for (int i=1; i<=E; i++) {
        if (!removed[i]) rSet.pb(i);
        else bSet.pb(i);
    }

    // Add forward edges for removing something from rSet and adding back in something from bSet in roy's graph.
    for (auto x: rSet) {
        for (auto y: bSet) {
            // if we can remove a non-removed edge and add a removed edge, we can connect the graph
            // then we connect those two edges together
            ge[x].in = false; ge[y].in = true;
            if (connected(biv)) matGraph.pb({x, y, FACTOR*ge[y].w +1LL, -1, true});   // x -> y
            if (connected(roy)) matGraph.pb({y, x, -FACTOR*ge[x].w +1LL, -1, true});  // y -> x
            ge[x].in = true; ge[y].in = false;
        }
    }
    /// now we form the matGraph, which as src for roy and des for biv (2 colors)
    /// if we remove a edge and the original graph is still connected, then it is connected from src to des (the problem condition is met)
    /// or if remove a non-removed edge and add a removed edge, we can connect the original graph, we link those 2 edge together, since those form the possible path from src to des as well
    /// this matGraph represents how we can exclude edge and still make the problem work

}

int main() {
    debug = false;
    ios_base::sync_with_stdio(false); cin.tie(0);

    cin >> N >> E;

    for(int i=1;i<=E;i++) {
        cin >> ge[i].u >> ge[i].v >> ge[i].w;
        ge[i].id = i; ge[i].in = true; removed[i] = false;
        totW += ge[i].w;

        int a = ge[i].u, b = ge[i].v;
        string str; cin >> str;
        if(str == "R" || str == "G") {  // Roy
            adj[roy][a].pb(mp(b,i));
            if(a!=b) adj[roy][b].pb(mp(a,i));
        }
        if(str == "B" || str == "G") {
            adj[biv][a].pb(mp(b,i));
            if(a!=b) adj[biv][b].pb(mp(a,i));
        }
    }

    // if no connectivity
    if(!connected(roy) || !connected(biv)) {
        for(int i=1; i<=E; i++) cout << -1 << endl;
        exit(0);
    }

    ll ans[MAXE];
    for(int i=0;i<=E;i++) ans[i] = -1LL;

    int idx = E;
    ans[E] = totW;
    idx--;

    // do matroid intersection one by one
    while(true && idx>0) {
        if(debug) cout << "work on " << idx << " edges" << endl;
        // Get the matroid graph - source is #e+1, dest is #(e+2)
        src = E+1; des = E+2;
        getMatGraph();

        // Bellman-Ford on matroid graph
        for(int i=0; i<=des; i++) {
            dist[i] = INF; p[i] = -1;
        }
        dist[src] = 0LL;
        for (int i=1; i<=des; i++) {
            for (auto item: matGraph) {
                if (dist[item.u] + item.w < dist[item.v]) {
                    dist[item.v] = dist[item.u] + item.w;
                    p[item.v] = item.u;
                }
            }
        }

        // Augmented our solution.
        if (dist[des] < INF) {
            // Build back path.
            vi path; path.clear();
            int cur = p[des];
            while (cur != src) {
                if(debug) cout << cur << " ";
                path.pb(cur); cur = p[cur];
            }
            if(debug) cout << " edges removed" << endl;

            // Flip all of these edges.
            for (int x: path) removed[x] = !removed[x];

            // Update solution for this many edges.
            ans[idx] = 0LL;
            for (int i=1; i<=E; i++)
                if (!removed[i]) ans[idx] += ge[i].w;

            // For next iteration.
            idx--;
        } else {
            break;
        }
    }

    for(int i=1; i<=E; i++) cout << ans[i] << endl;

    if(debug) cout << endl << "EOL" << endl;

}

/*
5 8
1 5 1 R
2 1 2 R
5 4 5 R
4 5 3 G
1 3 3 G
4 3 5 G
5 4 1 B
1 2 2 B
*/

详细

Test #1:

score: 100
Accepted
time: 1ms
memory: 3524kb

input:

5 8
1 5 1 R
2 1 2 R
5 4 5 R
4 5 3 G
1 3 3 G
4 3 5 G
5 4 1 B
1 2 2 B

output:

-1
-1
-1
-1
15
14
17
22

result:

ok 8 numbers

Test #2:

score: -100
Memory Limit Exceeded

input:

31 93
11 28 508 B
5 29 329 R
26 27 213 R
23 21 11 B
19 20 373 R
7 14 19 B
11 15 478 B
9 27 737 R
8 30 548 B
14 8 468 R
27 14 989 G
25 25 235 B
18 3 669 R
26 5 254 B
8 6 866 G
26 30 612 R
29 4 658 R
3 11 690 R
29 24 650 R
17 24 986 B
13 19 608 B
10 26 380 B
3 17 998 R
12 16 849 B
23 5 449 B
19 13 302...

output:


result: