牛客多校----E Room

链接:https://www.nowcoder.com/acm/contest/143/E
来源:牛客网

room
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Nowcoder University has 4n students and n dormitories ( Four students per dormitory). Students numbered from 1 to 4n.

And in the first year, the i-th dormitory ‘s students are (x1[i],x2[i],x3[i],x4[i]), now in the second year, Students need to decide who to live with.

In the second year, you get n tables such as (y1,y2,y3,y4) denote these four students want to live together.

Now you need to decide which dormitory everyone lives in to minimize the number of students who change dormitory.

输入描述:
The first line has one integer n.

Then there are n lines, each line has four integers (x1,x2,x3,x4) denote these four students live together in the first year

Then there are n lines, each line has four integers (y1,y2,y3,y4) denote these four students want to live together in the second year
输出描述:
Output the least number of students need to change dormitory.
示例1
输入
复制
2
1 2 3 4
5 6 7 8
4 6 7 8
1 2 3 5
输出
复制
2
说明
Just swap 4 and 5
备注:
1<=n<=100

1<=x1,x2,x3,x4,y1,y2,y3,y4<=4n

It’s guaranteed that no student will live in more than one dormitories.

假设新的宿舍里,第 i 个4人团体安排到第 j 间宿舍,那么不用搬的学生数量,
就是4人团体和原住民的交,那么费用就是用搬的学生数量,
变成带权二分图匹配问题,可以用费用流做(直接构完图用最小费用最大流模板求解)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int MAXN = 1010;
const int MAXM = 40010;

typedef struct Node{
    int s,to,next,capacity,value;
}Node;

int n,m;
int ecnt;
Node node[MAXM];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
bool vis[MAXN];

void init()
{
    ecnt = 0;
    memset(head,-1,sizeof(head));
    memset(node,0,sizeof(node));
}

void addEdge(int u,int v,int w,int c)
{
    node[ecnt].to = v;
    node[ecnt].s = u;
    node[ecnt].capacity = c;//流量
    node[ecnt].value = w;//路径长度是费用
    node[ecnt].next = head[u];
    head[u] = ecnt++;
    node[ecnt].to = u;
    node[ecnt].s = v;
    node[ecnt].capacity = 0;//流量
    node[ecnt].value = -w;//路径长度是费用
    node[ecnt].next = head[v];
    head[v] = ecnt++;
}

bool spfa(int s,int t,int nnum)
{
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i = 0;i <= nnum;++i)
    {
        dis[i] = inf;
    }
    queue<int>que;
    que.push(s);
    dis[s] = 0;
    vis[s] = true;
    while(!que.empty())
    {
        int temp = que.front();
        que.pop();
        vis[temp] = false;
        for(int i = head[temp];i + 1;i = node[i].next)
        {
            if(node[i].capacity)
            {
                int ne = node[i].to;
                if(dis[temp] + node[i].value < dis[ne]){
                    dis[ne] = dis[temp] + node[i].value;
                    pre[ne] = i;
                    if(!vis[ne]){
                        que.push(ne);
                        vis[ne] = true;
                    }
                }
            }
        }
    }
    if(dis[t] == inf)
        return false;
    return true;
}

int getMincost(int s,int t,int nnum)
{
    int ans_flow = 0;
    int ans_cost = 0;
    int temp,minc;
    while(spfa(s,t,nnum))
    {
//        cout << 0 << endl;
        temp = t;
        minc = inf;
        while(pre[temp] != -1)
        {
            minc = min(node[pre[temp]].capacity,minc);
            temp = node[pre[temp]].s;
        }
        temp = t;
        while(pre[temp] != -1)
        {
            node[pre[temp]].capacity -= minc;
            int ss = pre[temp] ^ 1;
            node[ss].capacity += minc;
            temp = node[pre[temp]].s;
        }
        ans_cost += dis[t] * minc;
    }
    return ans_cost;
}

typedef struct room{
    int num[4];
}room;
room a[MAXN],b[MAXN];

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i = 0;i < n;++i)
        {
            for(int j = 0;j < 4;++j)
            {
                scanf("%d",&a[i].num[j]);
            }
        }
        for(int i = 0;i < n;++i)
        {
            for(int j = 0;j < 4;++j)
            {
                scanf("%d",&b[i].num[j]);
            }
        }
        for(int i = 0;i < n;++i)
        {
            for(int j = 0;j < n;++j)
            {
                int v = 0;
                for(int k = 0; k < 4;++k)
                {
                    for(int p = 0;p < 4;++p)
                    {
                        if(a[i].num[k] == b[j].num[p])
                            v++;
                    }
                }
                //第 i 个4人团体安排到第 j 间宿舍,需要搬的学生数量
                //只能搬一次,所以边的容量为1
                addEdge(i + 1,n + j + 1,4 - v,1);
            }
        }
        //添加源点和汇点
        //与源点和汇点连接的边费用为0
        for(int i = 0;i < n;++i)
        {
            addEdge(0,i + 1,0,1);
            addEdge(n + i + 1,2 * n + 1,0,1);
        }
        int ans;
        printf("%d\n",getMincost(0,2 * n + 1,2 * n + 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/81368555