Glorious Brilliance (最短路 + 带权二分图匹配)

Posted wethura

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glorious Brilliance (最短路 + 带权二分图匹配)相关的知识,希望对你有一定的参考价值。

这是一道代码大题。一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!!

把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建图,利用二分图KM算法去匹配最优方案。然后求出每一组更换的,利用原先已经求好的路径去储存答案。

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

const int inf  = 0x3f3f3f3f;
const int maxn = 5e2 + 7;
vector<pair<int, int> >ANS;
vector<int>Gra[maxn], path[maxn][maxn], X, Y, Left, Right;
char str[maxn];
int g[maxn][maxn], col[maxn], *pairr, pairr1[maxn], pairr2[maxn];
int mp[maxn][maxn], lx[maxn], ly[maxn], linker[maxn], slack[maxn];
int n, m, l, nx, ny;
bool vis[maxn], visx[maxn], visy[maxn];

bool DFS(int x){
    visx[x] = true;
    for(int y = 0; y < ny; y++) {
        if(visy[y])
            continue;
        int tmp = lx[x] + ly[y] - mp[x][y];
        if(tmp == 0) {
            visy[y] = true;
            if(linker[y] == -1 || DFS(linker[y])) {
                linker[y] = x;
                return true;
            }
        } else if(slack[y] > tmp)
            slack[y] = tmp;
    }
    return false;
}

int KM(){
    memset(linker,-1,sizeof(linker));
    memset(ly,0,sizeof(ly));
    for(int i = 0; i < nx; i++) {
        lx[i] = -inf;
        for(int j = 0; j < ny; j++)
            if(mp[i][j] > lx[i])
                lx[i] = mp[i][j];
    }
    for(int x = 0; x < nx; x++) {
        for(int i = 0; i < ny; i++)
            slack[i] = inf;
        while(true) {
            memset(visx,false,sizeof(visx));
            memset(visy,false,sizeof(visy));
            if(DFS(x))
                break;
            int d = inf;
            for(int i = 0; i < ny; i++)
                if(!visy[i] && d > slack[i])
                    d = slack[i];
            for(int i = 0; i < nx; i++)
                if(visx[i])
                    lx[i] -= d;
            for(int i = 0; i < ny; i++) {
                if(visy[i])
                    ly[i] += d;
                else
                    slack[i] -= d;
            }
        }
    }
    int res = 0;
    for(int i = 0; i < ny; i++)
        if(linker[i] != -1)
            res -= mp[linker[i]][i];
    return res;
}

void getMinRoad(int u){
    queue<int>que;while(!que.empty())que.pop();
    que.push(u);g[u][u] = 0;
    path[u][u].push_back(u);
    memset(vis, false, sizeof(vis));
    vis[u] = true;

    while(!que.empty()){
        int st = que.front();que.pop();

        for(auto to : Gra[st]){
            if(vis[to]) continue;
            vis[to] = true;
            g[u][to] = g[u][st] + 1;
            path[u][to] = path[u][st];
            path[u][to].push_back(to);
            que.push(to);
        }
    }
}

bool color(int st){
    queue<int> que;while(!que.empty())que.pop();
    X.push_back(st);
    que.push(st);
    col[st] = 0;
    while(!que.empty()){
        int u = que.front();que.pop();

        for(auto v : Gra[u]){
            if(col[v] == col[u]) return false;
            if(col[v] != -1) continue;
            col[v] = col[u] ^ 1;
            if(col[v]) Y.push_back(v);
            else X.push_back(v);

            que.push(v);
        }
    }
    return true;
}

void GetAns(int u, int v, int setp){
    if(u == v) return ;
    vector<int>&tmp = path[u][v];
    for(int i = 0; i < tmp.size() - 1; i ++)
    if(str[tmp[i]] != str[tmp[i +1]]){
        ANS.push_back(make_pair(tmp[i], tmp[i + 1]));
        swap(str[tmp[i]], str[tmp[i + 1]]);
        GetAns(u, tmp[i], setp + 1);
        GetAns(tmp[i + 1], v, setp + 1);
        return ;
    }
}

int getSum(vector<int>A, vector<int>B, int Pair[]){
    Left.clear(); Right.clear();
    for(auto x : A) if(str[x] == 1) Left.push_back(x);
    for(auto x : B) if(str[x] == 0) Right.push_back(x);

    nx = ny = Left.size();
    for(int i = 0; i < nx; i ++)
        for(int j = 0; j < ny; j ++)
            mp[i][j] = - g[Left[i]][Right[j]];
    int ret = KM();

    for(int i = 0; i < nx; i ++){
        int u = Right[i], v = Left[linker[i]];
        Pair[u] = v;Pair[v] = u;
    }
    return ret;
}

bool solve(int st){
    int zero = 0, sum1 = inf, sum2 = inf;
    X.clear(), Y.clear();
    if(!color(st)) return 0;
    for(auto x : X) if(str[x] == 0) zero ++;
    for(auto x : Y) if(str[x] == 0) zero ++;

    if(zero == X.size()) sum1 = getSum(X, Y, pairr1);
    if(zero == Y.size()) sum2 = getSum(Y, X, pairr2);

    if(sum1 == inf && sum2 == inf) return false;
    pairr = sum1 > sum2 ? pairr2 : pairr1;
    for(auto x : X) if(pairr[x] != -1) GetAns(x, pairr[x], 1);

    return true;
}

void init(){
    memset(pairr1, -1, sizeof(pairr1));
    memset(pairr2, -1, sizeof(pairr2));
    memset(slack, 0, sizeof(slack));
    for(int i = 1; i <= n; i ++){
        Gra[i].clear();
        col[i] = -1;
        for(int j = 1; j <= n; j ++){
            g[i][j] = inf;
            path[i][j].clear();
        }
    }
    ANS.clear();
}

int main(){
    int T,a,b;scanf("%d",&T);
    while(T --){
        scanf("%d%d%s", &n, &m, str + 1);
        init();
        for(int i = 0; i < m; i ++){
            scanf("%d%d",&a,&b);
            Gra[a].push_back(b);
            Gra[b].push_back(a);
        }
        for(int i = 1; i <= n; i ++) getMinRoad(i);

        bool flag = true;
        for(int i = 1; i <= n; i ++){
            if(col[i] == -1 && !solve(i)){
                flag = false;break;
            }
        }
        if(!flag){
            printf("-1
");
            continue;
        }
        printf("%d
", ANS.size());
        for(int i = 0; i < ANS.size(); i ++){
            printf("%d %d
",ANS[i].first, ANS[i].second);
        }
    }
    return 0;
}

 

以上是关于Glorious Brilliance (最短路 + 带权二分图匹配)的主要内容,如果未能解决你的问题,请参考以下文章

❤️数据结构入门❤️(3 - 5)- 单源最短路

数据结构—— 图:最短路径问题

算法导论——单元最短路径

最短路径 深入浅出Dijkstra算法(一)

最短路径 Dijkstra 算法为啥边上的权值非负阿?

[最短路] aw920. 最优乘车(单源最短路建图+bfs最短路模型+知识理解+好题)