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\n");
            continue;
        }
        printf("%d\n", ANS.size());
        for(int i = 0; i < ANS.size(); i ++){
            printf("%d %d\n",ANS[i].first, ANS[i].second);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wethura/p/9771743.html

时间: 2024-10-09 10:26:25

Glorious Brilliance (最短路 + 带权二分图匹配)的相关文章

费用流模板(带权二分图匹配)——hdu1533

/* 带权二分图匹配 用费用流求,增加源点s 和 汇点t */ #include<bits/stdc++.h> using namespace std; #define maxn 10005 #define maxm 200005 struct Edge{int to,nxt,w,c;}e[maxm<<1]; int head[maxn],tot,n,m,s,t,ans,maxflow; char mp[maxn][maxn]; vector<pair<int,int&

hdu5045:带权二分图匹配

题目大意 : n个人 做m道题,其中 每连续的n道必须由不同的人做 已知第i人做出第j题的概率为pij,求最大期望 思路:考虑每连续的n道题 都要n个人来做,显然想到了带权的二分图匹配 然后就是套模板了 代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h>

带权二分图的最大权匹配 KM算法模版

带权二分图的最大权匹配 KM算法模版 下面是kuangbin大神的模版,已通过西电oj1048的测试 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set

KM(Kuhn-Munkres)算法求带权二分图的最佳匹配

KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后,这些概念的意义和背后的作用就渐渐的显示出来了.因此,先暂时把相关概念列出来,看看,有个大概印象就好,等到了解了算法的流程后,在看原理中会有这些概念,那个时候回来细看就好了. 完备匹配:定义 设G=<V1,V2,E>为二部图,|V1|≤|V2|,M为G中一个最大匹配,且|M|=|V1|,则称M为V1

二分图与网络流 带权二分图的最大匹配

二分图与网络流  带权二分图的最大匹配 在某书上偶然发现,二分图和网络流是有联系的,在子图u中建立超级源点,在子图v中建立超级汇点,源点到u和汇点到v的每条边容量设为1,u和v中的边的容量也设为1,求出最大流也就是原二分图的最大匹配了. 而求带权二分图的最大匹配也就很容易了,将u和v的权值设为容量,仍然建立超级源点和超级汇点转为网络流解决即可. 真是一切皆可网络流啊...

&quot;《算法导论》之‘图’&quot;:不带权二分图最大匹配(匈牙利算法)

博文“二分图的最大匹配.完美匹配和匈牙利算法”对二分图相关的几个概念讲的特别形象,特别容易理解.本文介绍部分主要摘自此博文. 还有其他可参考博文: 趣写算法系列之--匈牙利算法 用于二分图匹配的匈牙利算法 1. 前言 二分图:简单来说,如果图中点可以被分为两组,并且使得所有边都跨越组的边界,则这就是一个二分图.准确地说:把一个图的顶点划分为两个不相交集 U 和V ,使得每一条边都分别连接U.V中的顶点.如果存在这样的划分,则此图为一个二分图.二分图的一个等价定义是:不含有「含奇数条边的环」的图.

KM算法【带权二分图完美匹配】

先orz litble--KM算法 为什么要用KM算法 因为有的题丧心病狂卡费用流 KM算法相比于费用流来说,具有更高的效率. 算法流程 我们给每一个点设一个期望值[可行顶标] 对于左边的点来说,就是期望能匹配到多大权值的右边的点 对于右边的点来说,就是期望能在左边的点的期望之上还能产生多少贡献 两个点能匹配,当且仅当它们的期望值之和为这条边的权值 一开始初始化所有左点的期望是其出边的最大值,因为最理想情况下当然是每个点都匹配自己能匹配最大的那个 右点期望为0 然后我们逐个匹配,当一个点匹配失败

Kuhn-Munkres算法。带权二分图匹配模板 (bin神小改版本)

/****************************************************** 二分图最佳匹配 (kuhn munkras 算法 O(m*m*n)). 邻接矩阵形式 . 返回最佳匹配值,传入二分图大小m,n 邻接矩阵 map ,表示权,m1,m2返回一个最佳匹配,为匹配顶点的match值为-1, 一定注意m<=n,否则循环无法终止,最小权匹配可将全职取相反数. 初始化: for(i=0;i<MAXN;i++) for(j=0;j<MAXN;j++) mat

算法讲解:二分图匹配

算法讲解:二分图匹配 二分图匹配,自然要先从定义入手,那么二分图是什么呢? 二分图: 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图. 简单的说,一个图被分成了两部分,相同的部分没有边,那这个图就是二分图,二分图是特殊的图. 匹配: 给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两