HDU 4619 Warm up 2(最大独立集)

HDU 4619 Warm up 2

Problem Description
Some 1×2 dominoes are placed on a plane. Each dominoe is placed either horizontally or vertically. It’s guaranteed the dominoes in the same direction are not overlapped, but horizontal and vertical dominoes may overlap with each other. You task is to remove some dominoes, so that the remaining dominoes do not overlap with each other. Now, tell me the maximum number of dominoes left on the board.

Input
There are multiple input cases.The first line of each case are 2 2 integers: n ( 1 < = n < = 1000 ) , m ( 1 < = m < = 1000 ) n(1 <= n <= 1000), m(1 <= m <= 1000) , indicating the number of horizontal and vertical dominoes.
Then n n lines follow, each line contains 2 2 integers x ( 0 < = x < = 100 ) x (0 <= x <= 100) and y ( 0 < = y < = 100 ) y (0 <= y <= 100) , indicating the position of a horizontal dominoe. The dominoe occupies the grids of ( x , y ) (x, y) and ( x + 1 , y ) (x + 1, y)
Then m m lines follow, each line contains 2 2 integers x ( 0 < = x < = 100 ) x (0 <= x <= 100) and y ( 0 < = y < = 100 ) y (0 <= y <= 100) , indicating the position of a horizontal dominoe. The dominoe occupies the grids of ( x , y ) (x, y) and ( x , y + 1 ) (x, y + 1) .
Input ends with n = 0 n = 0 and m = 0 m = 0 .

Output
For each test case, output the maximum number of remaining dominoes in a line.

Sample Input

2 3
0 0
0 3
0 1
1 1
1 3
4 5
0 1
0 2
3 1
2 2
0 0
1 0
2 0
4 1
3 2
0 0

Sample Output

4
6

\bullet 题意:有 n n 条水平和 m m 条竖直的单位长度的线段,规定同为水平或者竖直的线段怎么放都不算重叠,只有水平和竖直的线段有交点的时候算重叠。输入 n n 个点 ( x , y ) (x,y) 那么这条水平线段的令一个端点就是 ( x + 1 , y ) (x+1,y) ,再输入 m m 个坐标代表竖直线段。问从坐标系中找出最多多少条的线段,这些线段不能重叠。
\bullet 思路:刚学二分最大匹配可能想不到怎么做这个题,建议先去了解一下最大独立集,最大独立集=顶点数-最大匹配边数。什么是最大独立集:在二分图中选出最多的点,使得任意两两点之间都没有边,就是任意两两点之间都关系。既然这个题里要求最多的线段不重叠,那么就可以在有重叠的线段之间建边,然后再求最大独立集就行了。这个题建边是个麻烦事。
\bullet 题意我们可以用一个二维数组 v i s [ i ] [ j ] vis[i][j] 代表 ( i , j ) (i,j) 这个坐标已经被哪个顶点占用了(把线段抽象为顶点,顶点的编号就按照输入顺序编就行了),如果在某次输入顶点的坐标 ( x , y ) (x,y) 或者 ( x + 1 , y ) (x+1,y) 或者 ( x , y + 1 ) (x,y+1) 已经被前面的某个顶点占用了,那就在这两个顶点间建一条无向边,再把 v i s [ x ] [ y ] vis[x][y] v i s [ x + 1 ] [ y ] vis[x+1][y] v i s [ x ] [ y + 1 ] vis[x][y+1] 更新成当前的顶点的编号。这样就能在输入的时候就把边建好了。最后在跑一次匈牙利算法就行了,注意最后得到的最大匹配边数要➗2。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<iostream>
#include<queue>
#include<string>
#include<math.h>
typedef long long LL;
using namespace std;
const int maxn=1e4+10;
int n,m;
int vis[150][150],used[2500],match[2500];

struct node{int to,next;}e[maxn];///链式前向星存边
int cnt = 0,head[maxn];
void add(int s,int E)
{
    e[++cnt] = {E,head[s]};
    head[s] = cnt;
}

bool dfs(int x)///匈牙利算法
{
    if(used[x])return false;
    for(int i = head[x];i != -1;i = e[i].next){
        int to = e[i].to;
        if(!used[to]){
            used[to] = 1;
            if(match[to] == -1||dfs(match[to])){
                match[to] = x;
                return true;
            }
        }
    }
    return false;
}

void input()
{
    for(int i = 1;i <= n;i++){///输入n条水平的线段
        int x,y;
        scanf("%d%d",&x,&y);
        if(vis[x][y] != -1 && vis[x][y] != i){///注意不能和自己建边
            add(i,vis[x][y]);
            add(vis[x][y],i);
        }
        if(vis[x+1][y] != -1 && vis[x+1][y] != i){
            add(i,vis[x+1][y]);
            add(vis[x+1][y],i);
        }
        vis[x][y] = i;vis[x+1][y] = i;
    }
    for(int i = n+1;i <= m+n;i++){///输入m条竖直的线段
        int x,y;
        scanf("%d%d",&x,&y);
        if(vis[x][y] != -1 && vis[x][y] != i){
            add(i,vis[x][y]);
            add(vis[x][y],i);
        }
        if(vis[x][y+1] != -1 && vis[x][y+1] != i){
            add(i,vis[x][y+1]);
            add(vis[x][y+1],i);
        }
        vis[x][y] = i;vis[x][y+1] = i;
    }
}

void init()
{
    cnt = 0;
    memset(head,-1,sizeof(head));
    memset(e,0,sizeof(e));
    memset(vis,-1,sizeof(vis));///初始化为-1
    memset(match,-1,sizeof(match));
}

int main()
{
    while(scanf("%d%d",&n,&m) && n + m)
    {
        init();
        input();
        int ans = 0;
        for(int i = 1;i <= n + m;i++){
            memset(used,0,sizeof(used));
            if( dfs(i) )
                ans ++;
        }
        printf("%d\n",n + m - ( ans / 2 ));
    }
    return 0;
}

发布了34 篇原创文章 · 获赞 7 · 访问量 1883

猜你喜欢

转载自blog.csdn.net/qq_43628761/article/details/97130908
今日推荐