牛客多校 第五場 二分圖匹配 ROOM

作者:東林AotoriChiaki
鏈接:https://www.nowcoder.com/discuss/90015?type=101&order=0&pos=1&page=1
來源:牛客網

題意:有n個宿舍,每個宿舍住4個人,給定去年n個宿舍的人員構成,今年n個4人組合的情況,求最少幾個人需要搬寢室。

思路:轉化爲最小費用最大流解決的二分圖問題,對每個去年的宿舍,向每個今年的組合連一條邊,權值爲1費用爲需要搬的人數(4-相同的人數),源點到去年各點,今年各點到匯點,都連一條權值爲1費用爲0的最大流,跑一次費用流即可。

mycode:

自己踩的坑:book數組沒有初始化

費用流:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<iostream>
using namespace std;
struct node
{
    int u, to, w, c, next;//當前點,目的點,流量,費用,另一個目的點對應Map[]下標
};
#define inf 0x3f3f3f3f
node Map[162000];
int head[160500], vis[500], dist[500], pre[500], cnt;
void addedge(int u, int v, int w, int c)//前向星存圖
{
    Map[cnt].u = u;
    Map[cnt].to = v;
    Map[cnt].w = w;//正向爲w
    Map[cnt].c = c;//正向爲+
    Map[cnt].next = head[u];
    head[u] = cnt++;
    Map[cnt].u = v;
    Map[cnt].to = u;
    Map[cnt].w = 0;//反向爲0
    Map[cnt].c = -c;//反向爲-
    Map[cnt].next = head[v];
    head[v] = cnt++;
}
int spfa(int s, int e)//求最短路,記錄路徑
{
    memset(dist, inf, sizeof(dist));
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    queue<int> q;
    q.push(s);
    dist[s] = 0;
    while(!q.empty())
    {
        s = q.front();
        q.pop();
        vis[s] = 0;
        for(int i = head[s]; ~i; i = Map[i].next)
        {
            int to = Map[i].to, w = Map[i].w, c = Map[i].c;
            if(dist[to] > dist[s] + c && w)
            {
                dist[to] = dist[s] + c;
                pre[to] = i;
                if(!vis[to])
                {
                    vis[to] = 1;
                    q.push(to);
                }
            }
        }
    }
    if(pre[e] != -1) return 1;
    else return 0;
}
int Min_cost(int s, int e)
{
    int ans = 0;
    while(spfa(s, e))//能找到最短路,也就是增廣路
    {
        int max_flow = inf;
        int u = pre[e];
        while(u != -1)
        {
            max_flow = min(max_flow, Map[u].w);//這條增廣路,限制流量
            u = pre[Map[u].u];
        }
        u = pre[e];
        while(u != -1)//更新邊,和最小費用
        {
            Map[u].w -= max_flow;
            Map[u^1].w += max_flow;
            ans += max_flow * Map[u].c;
            u = pre[Map[u].u];
        }
    }
    return ans;
}
vector<int>da[500],da2[600];
int main()
{
    int n;
    memset(head,-1,sizeof head);
    cnt= 0;
    cin>>n;
    int a,b,c,d;
    for(int i=1; i<=n; i++)
    {
        cin>>a>>b>>c>>d;
        da[i].push_back(a);
        da[i].push_back(b);
        da[i].push_back(c);
        da[i].push_back(d);
        //sort(da[i].begin(),da[i].end());
    }
    for(int i=1; i<=n; i++)
    {
        cin>>a>>b>>c>>d;
        da2[i].push_back(a);
        da2[i].push_back(b);
        da2[i].push_back(c);
        da2[i].push_back(d);
        //sort(da2[i].begin(),da2[i].end());
    }
    int S =0,E = n+n+10;
    for(int i=1; i<=n; i++)
    {
        addedge(S,i,1,0);
    }
    for(int i=1; i<=n; i++)
    {
        addedge(i+n,E,1,0);
    }
    for(int i=1; i<=n; i++)
    {

        for(int p=1; p<=n; p++)
        {
            int cnt =0 ;
            for(int j=0; j<4; j++)
            {
                for(int k=0; k<4; k++)
                {
                    if(da[i][j]==da2[p][k])
                    {
                        cnt++;
                        break;
                    }
                }
            }
          //  cout<<cnt<<endl;
            addedge(i,p+n,1,4-cnt);
        }

    }
    int ans = Min_cost(S,E);
    cout<<ans<<endl;
    return 0;
}

KM算法:

#include<bits/stdc++.h>
using namespace std;
/* KM 算法
* 複雜度 O(nx*nx*ny)
* 求最大權匹配
* 若求最小權匹配,可將權值取相反數,結果取相反數
* 點的編號從 0 開始
*/
const int N = 3010;
const int INF = 0x3f3f3f3f;
int nx,ny;//兩邊的點數
int g[N][N];//二分圖描述
int linker[N],lx[N],ly[N];//y 中各點匹配狀態,x,y 中的點標號
int slack[N];
bool visx[N],visy[N];
bool DFS(int x)
{
    visx[x] = true;
    for(int y = 0; y < ny; y++)
    {
        if(visy[y])continue;
        int tmp = lx[x] + ly[y] - g[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(g[i][j] > lx[i])
                lx[i] = g[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 += g[linker[i]][i];
    return res;
}
////HDU 2255
//int main()
//{
//    int n;
//    while(scanf("%d",&n) == 1)
//    {
//        for(int i = 0; i < n; i++)
//            for(int j = 0; j < n; j++)
//                scanf("%d",&g[i][j]);
//        nx = ny = n;
//        printf("%d\n",KM());
//    }
//    return 0;
//}

vector<int>da[500],da2[600];
int main()
{
    int n;
    memset(visx,0,sizeof visx);
    memset(visy,0,sizeof visy);

    cin>>n;

    int a,b,c,d;
    for(int i=0; i<n; i++)
    {
        cin>>a>>b>>c>>d;
        da[i].push_back(a);
        da[i].push_back(b);
        da[i].push_back(c);
        da[i].push_back(d);
        //sort(da[i].begin(),da[i].end());
    }
    for(int i=0; i<n; i++)
    {
        cin>>a>>b>>c>>d;
        da2[i].push_back(a);
        da2[i].push_back(b);
        da2[i].push_back(c);
        da2[i].push_back(d);
        //sort(da2[i].begin(),da2[i].end());
    }

    for(int i=0; i<n; i++)
    {

        for(int p=0; p<n; p++)
        {
            int cnt =0 ;
            for(int j=0; j<4; j++)
            {
                for(int k=0; k<4; k++)
                {
                    if(da[i][j]==da2[p][k])
                    {
                        cnt++;
                        break;
                    }
                }
                g[i][p] = cnt;
                //ag[p][i] = 4-cnt;
            }

            //  cout<<cnt<<endl;

        }

    }
    nx  =ny =n;
    int ans = KM();
    cout<<4*n-ans<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章